From 801f8ce844680df1da6c197c0d3f79e7eb229114 Mon Sep 17 00:00:00 2001 From: Thomas Kain Date: Tue, 11 Aug 2026 22:59:24 -0400 Subject: [PATCH] Defer HUD player model refresh for loadout changes Right now, when the HUD's player model receives a post_inventory_application game event, it refreshes immediately in order to reflect the player's updated loadout. When this refresh is done, however, it doesn't see the player's updated loadout because it hasn't been reconciled by prediction yet. By deferring the model's refresh to our next think cycle, we ensure that this refresh only occurs after the player's loadout changes are known. --- src/game/client/tf/tf_hud_playerstatus.cpp | 11 +++++++---- src/game/client/tf/tf_hud_playerstatus.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/game/client/tf/tf_hud_playerstatus.cpp b/src/game/client/tf/tf_hud_playerstatus.cpp index 12bcf4376ae..2195f205e25 100644 --- a/src/game/client/tf/tf_hud_playerstatus.cpp +++ b/src/game/client/tf/tf_hud_playerstatus.cpp @@ -108,6 +108,7 @@ CTFHudPlayerClass::CTFHudPlayerClass( Panel *parent, const char *name ) : Editab m_nKillStreak = 0; m_bUsePlayerModel = cl_hud_playerclass_use_playermodel.GetBool(); + m_bModelPanelDirty = false; ListenForGameEvent( "localplayer_changedisguise" ); ListenForGameEvent( "post_inventory_application" ); @@ -233,10 +234,9 @@ void CTFHudPlayerClass::OnThink() bPlayerClassModeChange = true; } - bool bForceEyeUpdate = false; // set our class image - if ( m_nClass != pPlayer->GetPlayerClass()->GetClassIndex() || bTeamChange || bCloakChange || bLoadoutPositionChange || bPlayerClassModeChange || + if ( m_bModelPanelDirty || m_nClass != pPlayer->GetPlayerClass()->GetClassIndex() || bTeamChange || bCloakChange || bLoadoutPositionChange || bPlayerClassModeChange || ( m_nClass == TF_CLASS_SPY && ( @@ -411,6 +411,8 @@ static void HudPlayerClassUsePlayerModelDialogCallback( bool bConfirmed, void *p //----------------------------------------------------------------------------- void CTFHudPlayerClass::UpdateModelPanel() { + m_bModelPanelDirty = false; + if ( !m_bUsePlayerModel ) { return; @@ -547,12 +549,13 @@ void CTFHudPlayerClass::FireGameEvent( IGameEvent * event ) } else if ( FStrEq( "post_inventory_application", pszEventName ) ) { - // Force a refresh. if this is for the local player + // Force a refresh if this is for the local player. int iUserID = event->GetInt( "userid" ); C_TFPlayer* pPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); if ( pPlayer && pPlayer->GetUserID() == iUserID ) { - UpdateModelPanel(); + // Prediction won't have reconciled our loadout changes yet - defer our refresh to the next time we think. + m_bModelPanelDirty = true; } } else if ( FStrEq( "localplayer_pickup_weapon", pszEventName ) ) diff --git a/src/game/client/tf/tf_hud_playerstatus.h b/src/game/client/tf/tf_hud_playerstatus.h index e304b2c9364..3ebc353fd92 100644 --- a/src/game/client/tf/tf_hud_playerstatus.h +++ b/src/game/client/tf/tf_hud_playerstatus.h @@ -84,8 +84,8 @@ class CTFHudPlayerClass : public vgui::EditablePanel, public CGameEventListener int m_nLoadoutPosition; int m_nKillStreak; - bool m_bUsePlayerModel; + bool m_bModelPanelDirty; }; //-----------------------------------------------------------------------------