Added more infos to debug out hitboxes

This commit is contained in:
Kamay Xutax 2024-09-03 12:45:53 +02:00
parent ece2f9a81f
commit f4ded28fe0
8 changed files with 283 additions and 53 deletions

View file

@ -149,24 +149,8 @@ const unsigned int FCLIENTANIM_SEQUENCE_CYCLE = 0x00000001;
static CUtlVector< clientanimating_t > g_ClientSideAnimationList;
void RecvProxy_Sequence( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
// Have the regular proxy store the data.
RecvProxy_Int32ToInt32( pData, pStruct, pOut );
C_BaseAnimating *pAnimating = (C_BaseAnimating *)pStruct;
if ( !pAnimating )
return;
pAnimating->SetReceivedSequence();
// render bounds may have changed
pAnimating->UpdateVisibility();
}
IMPLEMENT_CLIENTCLASS_DT(C_BaseAnimating, DT_BaseAnimating, CBaseAnimating)
RecvPropInt(RECVINFO(m_nSequence), 0, RecvProxy_Sequence),
RecvPropInt(RECVINFO(m_nSequence)),
RecvPropInt(RECVINFO(m_nForceBone)),
RecvPropVector(RECVINFO(m_vecForce)),
RecvPropInt(RECVINFO(m_nSkin)),

View file

@ -521,9 +521,12 @@ private:
bool m_bWasFrozen;
int m_flPhysics;
public:
int m_nTickBase;
int m_nFinalPredictedTick;
public:
EHANDLE m_pCurrentVguiScreen;
bool m_bFiredWeapon;

View file

@ -16,6 +16,7 @@
#include "interpolatedvar.h"
#include "mathlib/vector.h"
#include "shareddefs.h"
#include "strtools.h"
#include "studio.h"
#include "util_shared.h"
#include "view.h"
@ -2145,10 +2146,14 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
if ( player && !player->IsLocalPlayer() )
{
const auto nAttackerTickBase = event->GetInt( "tickbase" );
const auto numhitboxes = event->GetInt( "num_hitboxes" );
QAngle angles[MAXSTUDIOBONES];
Vector positions[MAXSTUDIOBONES];
Assert( numhitboxes == player->GetModelPtr()->numbones() );
for ( int i = 0; i < numhitboxes; i++ )
{
char buffer[256];
@ -2175,11 +2180,12 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
// Let's see what the client thinks to check if there's any problems with hitboxes
float flBackupPoseParams[MAXSTUDIOPOSEPARAM];
float flBackupBoneControllers[MAXSTUDIOBONECTRLS];
C_AnimationLayer backupAnimLayers[C_BaseAnimatingOverlay::MAX_OVERLAYS];
Vector vecBackupPosition = player->GetAbsOrigin();
QAngle angBackupAngles = player->GetRenderAngles();
auto flOldCycle = GetCycle();
auto iOldSequence = GetSequence();
auto flOldCycle = player->GetCycle();
auto iOldSequence = player->GetSequence();
for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ )
{
@ -2191,13 +2197,13 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
flBackupBoneControllers[i] = player->m_flEncodedController[i];
}
for ( int i = 0; i < GetNumAnimOverlays(); i++ )
for ( int i = 0; i < player->GetNumAnimOverlays(); i++ )
{
backupAnimLayers[i] = *player->GetAnimOverlay(i);
}
player->SetSequence( event->GetInt( "sequence" ) );
player->SetCycle( event->GetFloat( "cycle" ) );
player->m_nSequence = event->GetInt( "sequence" );
player->m_flCycle = event->GetFloat( "cycle" );
player->SetAbsOrigin( Vector( event->GetFloat( "position_x" ),
event->GetFloat( "position_y" ),
event->GetFloat( "position_z" ) ) );
@ -2207,7 +2213,7 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
event->GetFloat( "angle_z" ) );
const auto numposeparams = event->GetInt( "num_poseparams" );
Assert( numposeparams == pStudioHdr->GetNumPoseParameters() );
Assert( numposeparams == player->GetModelPtr()->GetNumPoseParameters() );
for ( int i = 0; i < numposeparams; i++ )
{
@ -2218,7 +2224,7 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
}
const auto numbonecontrollers = event->GetInt( "num_bonecontrollers" );
Assert( numbonecontrollers == pStudioHdr->GetNumBoneControllers() );
Assert( numbonecontrollers == player->GetModelPtr()->GetNumBoneControllers() );
for ( int i = 0; i < numbonecontrollers; i++ )
{
@ -2252,17 +2258,168 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
animOverlay->m_fFlags = event->GetInt( buffer );
}
player->PushAllowBoneAccess( true, false, "Lag compensation context" );
// Let's see if anything wrong has happened, print some infos.
HitboxRecord* pRecord = nullptr;
for ( int i = 0; i < MAX_HISTORY_HITBOX_RECORDS; i++ )
{
pRecord = m_HitboxTrack[player->index].Get( i );
if ( pRecord && ( pRecord->m_nAttackerTickBase == nAttackerTickBase ) )
{
break;
}
}
if ( pRecord )
{
// Let's check what went wrong.
int pos = 0;
auto newOrigin = player->GetAbsOrigin();
if ( pRecord->m_vecAbsOrigin != newOrigin )
{
char buffer[256];
V_sprintf_safe( buffer,
"pos: %f != %f, %f != %f, %f != %f",
newOrigin.x,
pRecord->m_vecAbsOrigin.x,
newOrigin.y,
pRecord->m_vecAbsOrigin.y,
newOrigin.z,
pRecord->m_vecAbsOrigin.z );
NDebugOverlay::EntityTextAtPosition( pRecord->m_vecAbsOrigin, pos, buffer, flDuration );
pos++;
}
if ( pRecord->m_angRenderAngles != player->m_angRenderAngles )
{
char buffer[256];
V_sprintf_safe( buffer,
"angles: %f != %f, %f != %f, %f != %f",
player->m_angRenderAngles.x,
pRecord->m_angRenderAngles.x,
player->m_angRenderAngles.y,
pRecord->m_angRenderAngles.y,
player->m_angRenderAngles.z,
pRecord->m_angRenderAngles.z );
NDebugOverlay::EntityTextAtPosition( pRecord->m_vecAbsOrigin, pos, buffer, flDuration );
pos++;
}
if ( pRecord->m_flCycle != player->m_flCycle )
{
char buffer[256];
V_sprintf_safe( buffer, "cycle: %f != %f", player->m_flCycle, pRecord->m_flCycle );
NDebugOverlay::EntityTextAtPosition( pRecord->m_vecAbsOrigin, pos, buffer, flDuration );
pos++;
}
if ( pRecord->m_nSequence != player->m_nSequence )
{
char buffer[256];
V_sprintf_safe( buffer,
"sequence: %s(%i) != %s(%i)",
player->GetSequenceName( player->m_nSequence ),
player->m_nSequence,
player->GetSequenceName( pRecord->m_nSequence ),
pRecord->m_nSequence );
NDebugOverlay::EntityTextAtPosition( pRecord->m_vecAbsOrigin, pos, buffer, flDuration );
pos++;
}
auto mdl = player->GetModelPtr();
for ( int i = 0; i < mdl->GetNumPoseParameters(); i++ )
{
if ( pRecord->m_flPoseParameters[i] != player->m_flPoseParameter[i] )
{
char buffer[256];
V_sprintf_safe( buffer,
"pose parameter %s (%i): %f != %f",
mdl->pPoseParameter( i ).pszName(),
i,
player->m_flPoseParameter[i],
pRecord->m_flPoseParameters[i] );
NDebugOverlay::EntityTextAtPosition( pRecord->m_vecAbsOrigin, pos, buffer, flDuration );
pos++;
}
}
for ( int i = 0; i < mdl->GetNumBoneControllers(); i++ )
{
if ( pRecord->m_flEncodedControllers[i] != player->m_flEncodedController[i] )
{
char buffer[256];
V_sprintf_safe( buffer,
"bone controller %i (%i): %f != %f",
mdl->pBonecontroller( i )->bone,
i,
player->m_flEncodedController[i],
pRecord->m_flEncodedControllers[i] );
NDebugOverlay::EntityTextAtPosition( pRecord->m_vecAbsOrigin, pos, buffer, flDuration );
pos++;
}
}
for ( int i = 0; i < player->GetNumAnimOverlays(); i++ )
{
auto animOverlay = player->GetAnimOverlay( i );
if ( animOverlay->m_flCycle != pRecord->m_AnimationLayer[i].m_flCycle
|| animOverlay->m_flWeight != pRecord->m_AnimationLayer[i].m_flWeight
|| animOverlay->m_nSequence != pRecord->m_AnimationLayer[i].m_nSequence
|| animOverlay->m_nOrder != pRecord->m_AnimationLayer[i].m_nOrder
|| animOverlay->m_fFlags != pRecord->m_AnimationLayer[i].m_fFlags )
{
char buffer[256];
V_sprintf_safe( buffer,
"anim overlay %i: sequence: %s != %s ( %i != %i ), cycle: %f != %f, "
"weight: %f != %f, order %i != %i, flags: %i != %i",
i,
GetSequenceName( animOverlay->m_nSequence ),
GetSequenceName( pRecord->m_AnimationLayer[i].m_nSequence ),
animOverlay->m_nSequence,
pRecord->m_AnimationLayer[i].m_nSequence,
animOverlay->m_flCycle,
pRecord->m_AnimationLayer[i].m_flCycle,
animOverlay->m_flWeight,
pRecord->m_AnimationLayer[i].m_flWeight,
animOverlay->m_nOrder,
pRecord->m_AnimationLayer[i].m_nOrder,
animOverlay->m_fFlags,
pRecord->m_AnimationLayer[i].m_fFlags );
NDebugOverlay::EntityTextAtPosition( pRecord->m_vecAbsOrigin, pos, buffer, flDuration );
pos++;
}
}
}
else
{
DevMsg( "Could not get record info for player %s (%i) with tickbase %i\n",
player->GetPlayerName(),
player->index,
nAttackerTickBase );
}
player->PushAllowBoneAccess( true, false, "Lag compensation context" );
// Be sure we setup the bones again.
player->InvalidateBoneCache();
player->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
player->DrawClientHitboxes( cl_debug_duration.GetFloat(), false );
player->DrawClientHitboxes( flDuration, false );
player->PopBoneAccess( "Lag compensation context" );
// Set back original stuff.
player->SetSequence( iOldSequence );
player->SetCycle( flOldCycle );
player->m_nSequence = iOldSequence;
player->m_flCycle = flOldCycle;
player->SetAbsOrigin( vecBackupPosition );
player->m_angRenderAngles = angBackupAngles;

View file

@ -10,7 +10,6 @@
#pragma once
#endif
#include "cs_playeranimstate.h"
#include "c_baseplayer.h"
#include "cs_shareddefs.h"
@ -31,8 +30,6 @@ public:
int m_iAttachmentPoint; // Which attachment point on the player model this guy is on.
};
class C_CSPlayer : public C_BasePlayer, public ICSPlayerAnimStateHelpers
{
public:
@ -328,8 +325,10 @@ private:
bool m_bHasHelmet;
int m_iClass;
int m_ArmorValue;
public:
QAngle m_angEyeAngles;
QAngle m_angRenderAngles;
private:
bool m_bHasDefuser;
float m_fNextThinkPushAway;
@ -393,7 +392,36 @@ private:
int a,
float duration);
C_CSPlayer( const C_CSPlayer & );
C_CSPlayer( const C_CSPlayer& );
public:
// Around 256 bullets, should be way enough to debug out what happned...
static constexpr auto MAX_HISTORY_HITBOX_RECORDS = 256;
struct AnimLayerRecord
{
int m_nSequence;
float m_flCycle;
float m_flWeight;
int m_nOrder;
int m_fFlags;
};
struct HitboxRecord
{
int m_nAttackerTickBase;
Vector m_vecAbsOrigin;
QAngle m_angRenderAngles;
float m_flSimulationTime;
int m_nSequence;
float m_flCycle;
float m_flAnimTime;
AnimLayerRecord m_AnimationLayer[MAX_LAYER_RECORDS];
float m_flPoseParameters[MAXSTUDIOPOSEPARAM];
float m_flEncodedControllers[MAXSTUDIOBONECTRLS];
};
CUtlCircularBuffer< HitboxRecord, MAX_HISTORY_HITBOX_RECORDS > m_HitboxTrack[MAX_PLAYERS + 1];
};
C_CSPlayer* GetLocalOrInEyeCSPlayer( void );

View file

@ -683,8 +683,9 @@ void CBasePlayer::SetupVisibility( CBaseEntity *pViewEntity, unsigned char *pvs,
int CBasePlayer::UpdateTransmitState()
{
// TODO_ENHANCED: this fucks up animations.
// always call ShouldTransmit() for players
return SetTransmitState( FL_EDICT_FULLCHECK );
return SetTransmitState( FL_EDICT_ALWAYS );
}
int CBasePlayer::ShouldTransmit( const CCheckTransmitInfo *pInfo )

View file

@ -159,7 +159,7 @@ struct LagRecord
// If it can't get there, leave the player where he is.
//
ConVar sv_unlag_debug( "sv_unlag_debug", "0", FCVAR_GAMEDLL | FCVAR_DEVELOPMENTONLY );
ConVar sv_unlag_debug( "sv_unlag_debug", "0" );
float g_flFractionScale = 0.95;
@ -426,6 +426,8 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
// get track history of this player
auto track = &m_EntityTrack[pl_index];
bool foundSim = false;
bool foundAnim = false;
for ( int i = 0; i < MAX_TICKS_SAVED; i++ )
{
@ -443,11 +445,13 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
if ( flTargetSimTime == recordSim->m_flSimulationTime )
{
foundSim = true;
break;
}
if ( recordSim->m_flSimulationTime < flTargetSimTime )
{
foundSim = true;
prevRecordSim = track->Get( i - 1 );
break;
}
@ -464,6 +468,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
if ( recordAnim->m_flAnimTime == flTargetAnimTime )
{
foundAnim = true;
break;
}
}
@ -471,7 +476,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
Assert( recordAnim );
Assert( recordSim );
if ( !recordSim || !recordAnim )
if ( !foundAnim || !foundSim )
{
if ( sv_unlag_debug.GetBool() )
{
@ -489,7 +494,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
// so interpolate between these two records;
Assert( prevRecordSim->m_flSimulationTime > recordSim->m_flSimulationTime );
Assert( flTargetLerpSimTime < prevRecordSim->m_flSimulationTime );
Assert( flTargetSimTime < prevRecordSim->m_flSimulationTime );
// calc fraction between both records
fracSim = float( ( double( flTargetSimTime ) - double( recordSim->m_flSimulationTime ) )

View file

@ -7,6 +7,7 @@
#include "cbase.h"
#include "const.h"
#include "debugoverlay_shared.h"
#include "shareddefs.h"
#include "strtools.h"
#ifndef CLIENT_DLL
#include "player.h"
@ -526,16 +527,16 @@ void CCSPlayer::FireBullet(
#ifndef CLIENT_DLL
auto WritePlayerHitboxEvent = [&]( CBasePlayer* lagPlayer )
{
if ( IsBot() )
{
return;
}
IGameEvent* event = gameeventmanager->CreateEvent( "bullet_player_hitboxes" );
if ( event )
{
event->SetInt( "userid", GetUserID() );
event->SetInt( "player_index", lagPlayer->entindex() );
event->SetInt( "tickbase", TIME_TO_TICKS( GetTimeBase() ) );
event->SetInt( "bullet", iBullet );
event->SetFloat( "simtime", lagPlayer->GetSimulationTime() );
event->SetFloat( "animtime", lagPlayer->GetAnimTime() );
Vector positions[MAXSTUDIOBONES];
QAngle angles[MAXSTUDIOBONES];
@ -718,6 +719,8 @@ void CCSPlayer::FireBullet(
event->SetFloat( "dst_y", tr.endpos.y );
event->SetFloat( "dst_z", tr.endpos.z );
event->SetFloat( "radius", flBulletRadius );
event->SetInt( "tickbase", TIME_TO_TICKS( GetTimeBase() ) );
event->SetInt( "bullet", iBullet );
gameeventmanager->FireEvent( event );
}
#endif

View file

@ -1,6 +1,6 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
// Purpose:
//
//=============================================================================//
@ -9,6 +9,7 @@
#include "convar.h"
#include "mathlib/vector.h"
#include "usercmd.h"
#include "util_shared.h"
#include "weapon_csbase.h"
#ifndef CLIENT_DLL
@ -31,15 +32,15 @@ ConVar debug_screenshot_bullet_position("debug_screenshot_bullet_position", "0")
{
// If we have some sounds from the weapon classname.txt file, play a random one of them
const char *shootsound = pWeaponInfo->aShootSounds[ sound_type ];
const char *shootsound = pWeaponInfo->aShootSounds[ sound_type ];
if ( !shootsound || !shootsound[0] )
return;
CBroadcastRecipientFilter filter; // this is client side only
if ( !te->CanPredict() )
return;
CBaseEntity::EmitSound( filter, iPlayerIndex, shootsound, &vOrigin, flSoundTime );
CBaseEntity::EmitSound( filter, iPlayerIndex, shootsound, &vOrigin, flSoundTime );
}
class CGroupedSound
@ -51,7 +52,7 @@ ConVar debug_screenshot_bullet_position("debug_screenshot_bullet_position", "0")
CUtlVector<CGroupedSound> g_GroupedSounds;
// Called by the ImpactSound function.
void ShotgunImpactSoundGroup( const char *pSoundName, const Vector &vEndPos )
{
@ -109,7 +110,7 @@ ConVar debug_screenshot_bullet_position("debug_screenshot_bullet_position", "0")
// This runs on both the client and the server.
// On the server, it only does the damage calculations.
// On the client, it does all the effects.
void FX_FireBullets(
void FX_FireBullets(
int iPlayerIndex,
const Vector &vOrigin,
const QAngle &vAngles,
@ -183,7 +184,7 @@ void FX_FireBullets(
// #else
// V_strcat(szFlags, "SERVER ", sizeof(szFlags));
// #endif
//
//
if ( pPlayer->GetMoveType() == MOVETYPE_LADDER )
V_strcat(szFlags, "LADDER ", sizeof(szFlags));
@ -195,7 +196,7 @@ void FX_FireBullets(
float fVelocity = pPlayer->GetAbsVelocity().Length2D();
Msg("FireBullets @ %10f [ %s ]: inaccuracy=%f spread=%f max dispersion=%f mode=%2i vel=%10f seed=%3i %s\n",
Msg("FireBullets @ %10f [ %s ]: inaccuracy=%f spread=%f max dispersion=%f mode=%2i vel=%10f seed=%3i %s\n",
gpGlobals->curtime, weaponAlias, fInaccuracy, fSpread, fInaccuracy + fSpread, iMode, fVelocity, iSeed, szFlags);
}
#endif
@ -224,10 +225,10 @@ void FX_FireBullets(
// if this is server code, send the effect over to client as temp entity
// Dispatch one message for all the bullet impacts and sounds.
TE_FireBullets(
TE_FireBullets(
iPlayerIndex,
vHookedOrigin,
vAngles,
vHookedOrigin,
vAngles,
iWeaponID,
iMode,
iSeed,
@ -289,7 +290,7 @@ void FX_FireBullets(
if ( !pPlayer )
return;
StartGroupingSounds();
#ifdef GAME_DLL
@ -322,6 +323,54 @@ void FX_FireBullets(
y1[iBullet] = fRadius1 * sinf(fTheta1);
}
#ifdef CLIENT_DLL
static ConVarRef cl_showfirebullethitboxes("cl_showfirebullethitboxes");
static ConVarRef cl_showimpacts( "cl_showimpacts" );
if ( playerCmd && !playerCmd->hasbeenpredicted && ( cl_showfirebullethitboxes.GetBool() || cl_showimpacts.GetBool() ) )
{
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
auto lagPlayer = ( C_CSPlayer* )UTIL_PlayerByIndex( i );
if ( !lagPlayer )
{
continue;
}
C_CSPlayer::HitboxRecord record;
record.m_vecAbsOrigin = lagPlayer->GetRenderOrigin();
record.m_angRenderAngles = lagPlayer->m_angRenderAngles;
record.m_nAttackerTickBase = pPlayer->m_nTickBase;
record.m_flSimulationTime = lagPlayer->GetSimulationTime();
record.m_flAnimTime = lagPlayer->GetAnimTime();
record.m_flCycle = lagPlayer->GetCycle();
record.m_nSequence = lagPlayer->GetSequence();
lagPlayer->GetPoseParameters( lagPlayer->GetModelPtr(), record.m_flPoseParameters );
lagPlayer->GetBoneControllers( record.m_flEncodedControllers );
for ( int i = 0; i < lagPlayer->GetNumAnimOverlays(); i++ )
{
CAnimationLayer* layer = lagPlayer->GetAnimOverlay( i );
if ( layer )
{
record.m_AnimationLayer[i].m_flCycle = layer->m_flCycle;
record.m_AnimationLayer[i].m_nOrder = layer->m_nOrder;
record.m_AnimationLayer[i].m_nSequence = layer->m_nSequence;
record.m_AnimationLayer[i].m_flWeight = layer->m_flWeight;
record.m_AnimationLayer[i].m_fFlags = layer->m_fFlags;
}
}
pPlayer->m_HitboxTrack[lagPlayer->index].Push( record );
}
}
#endif
for ( int iBullet=0; iBullet < pWeaponInfo->m_iBullets; iBullet++ )
{
#ifdef CLIENT_DLL