From 368e6ec6fef713c93fe0b4d963f26a76da719d7e Mon Sep 17 00:00:00 2001 From: nullsystem <15316579+nullsystem@users.noreply.github.com> Date: Sat, 21 Mar 2026 10:53:04 +0000 Subject: [PATCH] Reset crosshair on resets to fix spectator non-matching-to-player xhair This is kind of a guesswork if it'll fix the spectator seeing crosshair on player that it's not the player's actual crosshair, but I'm assuming the state haven't been refreshed properly especialy the timer till next crosshair refresh and maybe on map change and where player index changes it gets stuck with other player's crosshair. * fixes #1735 --- src/game/client/hud_crosshair.cpp | 12 +++++++++- src/game/client/hud_crosshair.h | 2 ++ src/game/client/neo/c_neo_player.cpp | 32 +++++++++++++++++++++++++++ src/game/client/neo/c_neo_player.h | 1 + src/game/shared/neo/neo_gamerules.cpp | 17 ++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/game/client/hud_crosshair.cpp b/src/game/client/hud_crosshair.cpp index 0f326436d..41fc23938 100644 --- a/src/game/client/hud_crosshair.cpp +++ b/src/game/client/hud_crosshair.cpp @@ -377,6 +377,17 @@ void CHudCrosshair::GetDrawPosition ( float *pX, float *pY, bool *pbBehindCamera ConVar cl_neo_scope_restrict_to_rectangle("cl_neo_scope_restrict_to_rectangle", "1", FCVAR_CHEAT, "Whether to enforce rectangular sniper scope shape regardless of screen ratio.", true, 0.0, true, 1.0); +#ifdef NEO + +void CHudCrosshair::resetPlayersCrosshair() +{ + V_memset(m_szLocalStrPlayersCrosshair, 0, sizeof(m_szLocalStrPlayersCrosshair)); + V_memset(m_playersCrosshairInfos, 0, sizeof(m_playersCrosshairInfos)); + V_memset(m_aflLastCheckedPlayersCrosshair, 0, sizeof(m_aflLastCheckedPlayersCrosshair)); +} + +#endif // NEO + void CHudCrosshair::Paint( void ) { if ( !m_pCrosshair ) @@ -502,7 +513,6 @@ void CHudCrosshair::Paint( void ) if (bPlayerIdxValid) { bTakeSpecCrosshair = true; - m_playersCrosshairInfos; bThisFrameRefreshCrosshair = false; pCrosshairInfo = &m_playersCrosshairInfos[iPlayerIdx]; pszNeoCrosshair = pNeoPlayer->m_szNeoCrosshair.Get(); diff --git a/src/game/client/hud_crosshair.h b/src/game/client/hud_crosshair.h index ac4755dcf..7d19cd1b1 100644 --- a/src/game/client/hud_crosshair.h +++ b/src/game/client/hud_crosshair.h @@ -41,6 +41,8 @@ class CHudCrosshair : public CHudElement, public vgui::Panel char m_szLocalStrPlayersCrosshair[MAX_PLAYERS][NEO_XHAIR_SEQMAX] = {}; CrosshairInfo m_playersCrosshairInfos[MAX_PLAYERS] = {}; float m_aflLastCheckedPlayersCrosshair[MAX_PLAYERS] = {}; + + void resetPlayersCrosshair(); #endif virtual void SetCrosshairAngle( const QAngle& angle ); diff --git a/src/game/client/neo/c_neo_player.cpp b/src/game/client/neo/c_neo_player.cpp index 6e97c7421..7c96b59f5 100644 --- a/src/game/client/neo/c_neo_player.cpp +++ b/src/game/client/neo/c_neo_player.cpp @@ -474,6 +474,7 @@ C_NEO_Player::C_NEO_Player() m_bPreviouslyReloading = false; m_bLastTickInThermOpticCamo = false; m_bIsAllowedToToggleVision = false; + m_bSpecRefreshedStates = false; m_flTocFactor = 0.15f; @@ -1154,6 +1155,25 @@ void C_NEO_Player::PreThink( void ) m_flCamoAuxLastTime = 0; } + if (IsLocalPlayer() && GetTeamNumber() == TEAM_SPECTATOR) + { + if (NEORules()->IsRoundPreRoundFreeze()) + { + if (false == m_bSpecRefreshedStates) + { + if (CHudCrosshair *crosshair = GET_HUDELEMENT(CHudCrosshair)) + { + crosshair->resetPlayersCrosshair(); + } + } + m_bSpecRefreshedStates = true; + } + else + { + m_bSpecRefreshedStates = false; + } + } + if (IsAlive()) { if (IsLocalPlayer() && m_bFirstAliveTick) @@ -1168,6 +1188,11 @@ void C_NEO_Player::PreThink( void ) // so it could arrive too late. CLocalPlayerFilter filter; enginesound->SetPlayerDSP(filter, 0, true); + + if (CHudCrosshair *crosshair = GET_HUDELEMENT(CHudCrosshair)) + { + crosshair->resetPlayersCrosshair(); + } } } else @@ -1606,6 +1631,13 @@ void C_NEO_Player::Spawn( void ) } } } + + // Only do crosshair reset for confirmed local player + if (CHudCrosshair *crosshair = GET_HUDELEMENT(CHudCrosshair); + crosshair && IsLocalPlayer()) + { + crosshair->resetPlayersCrosshair(); + } } void C_NEO_Player::DoImpactEffect( trace_t &tr, int nDamageType ) diff --git a/src/game/client/neo/c_neo_player.h b/src/game/client/neo/c_neo_player.h index 283a199c4..590769b11 100644 --- a/src/game/client/neo/c_neo_player.h +++ b/src/game/client/neo/c_neo_player.h @@ -252,6 +252,7 @@ class C_NEO_Player : public C_HL2MP_Player bool m_bFirstDeathTick; bool m_bPreviouslyReloading; bool m_bIsAllowedToToggleVision; + bool m_bSpecRefreshedStates; float m_flLastAirborneJumpOkTime; float m_flLastSuperJumpTime; diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/neo_gamerules.cpp index 8f8f16217..e484431d2 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/neo_gamerules.cpp @@ -16,6 +16,7 @@ #include "engine/IEngineSound.h" #include "filesystem.h" #include "hltvcamera.h" +#include "hud_crosshair.h" #else #include "neo_player.h" #include "team.h" @@ -745,6 +746,17 @@ void CNEORules::ClientSpawned(edict_t* pPlayer) } #endif #endif + +#ifdef CLIENT_DLL + C_NEO_Player *pLocalPlayer = C_NEO_Player::GetLocalNEOPlayer(); + if (pLocalPlayer->index == pPlayer->m_EdictIndex) + { + if (CHudCrosshair *crosshair = GET_HUDELEMENT(CHudCrosshair)) + { + crosshair->resetPlayersCrosshair(); + } + } +#endif } int CNEORules::DefaultFOV(void) @@ -822,6 +834,11 @@ void CNEORules::ResetMapSessionCommon() m_pJuggernautItem = nullptr; m_pJuggernautPlayer = nullptr; m_bGotMatchWinner = false; +#else // CLIENT_DLL + if (CHudCrosshair *crosshair = GET_HUDELEMENT(CHudCrosshair)) + { + crosshair->resetPlayersCrosshair(); + } #endif }