From c8191426459c550ef1372209158584d03941fcca Mon Sep 17 00:00:00 2001 From: nullsystem <15316579+nullsystem@users.noreply.github.com> Date: Thu, 6 Aug 2026 20:18:06 +0100 Subject: [PATCH 1/2] Remove crosshair network from (C)NEOPlayer datatable, simplify caching Crosshair is already now networked in player resource, so no longer needed to be networked from server to client in (C)NEOPlayer and turned into a simple array server-side. The networked crosshair caching also simplified in client-side crosshair HUD. --- src/game/client/hud_crosshair.cpp | 37 ++++++++++++++++----------- src/game/client/hud_crosshair.h | 8 +++--- src/game/client/neo/c_neo_player.cpp | 2 -- src/game/client/neo/c_neo_player.h | 1 - src/game/server/neo/neo_player.cpp | 3 --- src/game/server/neo/neo_player.h | 2 +- src/game/server/player_resource.cpp | 5 ++-- src/game/shared/neo/neo_gamerules.cpp | 5 ++-- 8 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/game/client/hud_crosshair.cpp b/src/game/client/hud_crosshair.cpp index 3823402536..6497c30052 100644 --- a/src/game/client/hud_crosshair.cpp +++ b/src/game/client/hud_crosshair.cpp @@ -373,9 +373,9 @@ ConVar cl_neo_scope_restrict_to_rectangle("cl_neo_scope_restrict_to_rectangle", 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)); + V_memset(m_szLocalStrPlayerCrosshair, 0, sizeof(m_szLocalStrPlayerCrosshair)); + m_flLastCheckedXHair = 0.0f; + m_iPrevPlayerIdx = -1; } #endif // NEO @@ -495,7 +495,6 @@ void CHudCrosshair::Paint( void ) bool bThisFrameRefreshCrosshair = m_bRefreshCrosshair; auto *pNeoPlayer = static_cast(pPlayer); bool bTakeSpecCrosshair = false; - CrosshairInfo *pCrosshairInfo = &m_crosshairInfo; const char *pszNeoCrosshair = cl_neo_crosshair.GetString(); if (cl_neo_crosshair_network.GetBool() && IsLocalPlayerSpectator()) { @@ -504,34 +503,42 @@ void CHudCrosshair::Paint( void ) Assert(bPlayerIdxValid); if (bPlayerIdxValid) { + if (m_iPrevPlayerIdx != iPlayerIdx) + { + m_flLastCheckedXHair = 0.0f; + m_iPrevPlayerIdx = iPlayerIdx; + } bTakeSpecCrosshair = true; bThisFrameRefreshCrosshair = false; - pCrosshairInfo = &m_playersCrosshairInfos[iPlayerIdx]; - pszNeoCrosshair = pNeoPlayer->m_szNeoCrosshair.Get(); + pszNeoCrosshair = g_PR->GetNeoCrosshair(iPlayerIdx); // NEO NOTE (nullsystem): Only check the string per second static constexpr float FL_XHAIR_REFRESH_INTERVAL = 1.0f; - if (m_aflLastCheckedPlayersCrosshair[iPlayerIdx] + FL_XHAIR_REFRESH_INTERVAL < gpGlobals->curtime) + if (m_flLastCheckedXHair + FL_XHAIR_REFRESH_INTERVAL < gpGlobals->curtime) { - m_aflLastCheckedPlayersCrosshair[iPlayerIdx] = gpGlobals->curtime; - bThisFrameRefreshCrosshair = (V_strcmp(m_szLocalStrPlayersCrosshair[iPlayerIdx], pszNeoCrosshair) != 0); + m_flLastCheckedXHair = gpGlobals->curtime; + bThisFrameRefreshCrosshair = (V_strcmp(m_szLocalStrPlayerCrosshair, pszNeoCrosshair) != 0); if (bThisFrameRefreshCrosshair) { - V_strcpy_safe(m_szLocalStrPlayersCrosshair[iPlayerIdx], pszNeoCrosshair); + V_strcpy_safe(m_szLocalStrPlayerCrosshair, pszNeoCrosshair); } } - } } + else if (m_iPrevPlayerIdx != pNeoPlayer->entindex()) + { + bThisFrameRefreshCrosshair = true; + m_iPrevPlayerIdx = pNeoPlayer->entindex(); + } if (bThisFrameRefreshCrosshair) { - const bool bImported = ImportCrosshair(pCrosshairInfo, pszNeoCrosshair); + const bool bImported = ImportCrosshair(&m_crosshairInfo, pszNeoCrosshair); if (!bImported) { // NEO NOTE (nullsystem): Don't revert, just enforce default if it // is not given properly - ResetCrosshairToDefault(pCrosshairInfo); + ResetCrosshairToDefault(&m_crosshairInfo); } if (!bTakeSpecCrosshair) { @@ -552,9 +559,9 @@ void CHudCrosshair::Paint( void ) iNeoXHairWep += CROSSHAIR_WEP_DEFAULT_HIPFIRE; } eNeoXHairWep = static_cast( - UseCrosshairIndexFor(pCrosshairInfo, iNeoXHairWep, &bHideCrosshair)); + UseCrosshairIndexFor(&m_crosshairInfo, iNeoXHairWep, &bHideCrosshair)); } - CrosshairWepInfo *crh = &pCrosshairInfo->wep[eNeoXHairWep]; + CrosshairWepInfo *crh = &m_crosshairInfo.wep[eNeoXHairWep]; const int iTexXHId = m_iTexXHId[clamp(crh->iStyle, 0, CROSSHAIR_STYLE__TOTAL - 1)]; bool showFriendlyFireCrosshair = false; diff --git a/src/game/client/hud_crosshair.h b/src/game/client/hud_crosshair.h index 7d19cd1b1c..95743acdc2 100644 --- a/src/game/client/hud_crosshair.h +++ b/src/game/client/hud_crosshair.h @@ -37,10 +37,10 @@ class CHudCrosshair : public CHudElement, public vgui::Panel bool m_bRefreshCrosshair = true; CrosshairInfo m_crosshairInfo = {}; - // m_szLocalStrPlayersCrosshair is just for crosshair refresh checks - char m_szLocalStrPlayersCrosshair[MAX_PLAYERS][NEO_XHAIR_SEQMAX] = {}; - CrosshairInfo m_playersCrosshairInfos[MAX_PLAYERS] = {}; - float m_aflLastCheckedPlayersCrosshair[MAX_PLAYERS] = {}; + // m_szLocalStrPlayerCrosshair is just for crosshair refresh checks + char m_szLocalStrPlayerCrosshair[NEO_XHAIR_SEQMAX] = {}; + float m_flLastCheckedXHair = 0.0f; + int m_iPrevPlayerIdx = -1; void resetPlayersCrosshair(); #endif diff --git a/src/game/client/neo/c_neo_player.cpp b/src/game/client/neo/c_neo_player.cpp index 0b6563fae7..5f62921762 100644 --- a/src/game/client/neo/c_neo_player.cpp +++ b/src/game/client/neo/c_neo_player.cpp @@ -103,7 +103,6 @@ IMPLEMENT_CLIENTCLASS_DT(C_NEO_Player, DT_NEO_Player, CNEO_Player) RecvPropInt(RECVINFO(m_NeoFlags)), RecvPropString(RECVINFO(m_szNeoName)), RecvPropString(RECVINFO(m_szNeoClantag)), - RecvPropString(RECVINFO(m_szNeoCrosshair)), RecvPropInt(RECVINFO(m_szNameDupePos)), RecvPropBool(RECVINFO(m_bClientWantNeoName)), @@ -444,7 +443,6 @@ C_NEO_Player::C_NEO_Player() m_iNeoStar = NEO_DEFAULT_STAR; V_memset(m_szNeoName.GetForModify(), 0, sizeof(m_szNeoName)); V_memset(m_szNeoClantag.GetForModify(), 0, sizeof(m_szNeoClantag)); - V_memset(m_szNeoCrosshair.GetForModify(), 0, sizeof(m_szNeoCrosshair)); m_iLoadoutWepChoice = NEORules()->GetForcedWeapon() >= 0 ? NEORules()->GetForcedWeapon() : 0; m_iNextSpawnClassChoice = NEO_CLASS_RANDOM; diff --git a/src/game/client/neo/c_neo_player.h b/src/game/client/neo/c_neo_player.h index 366b911751..26ee56d4b8 100644 --- a/src/game/client/neo/c_neo_player.h +++ b/src/game/client/neo/c_neo_player.h @@ -252,7 +252,6 @@ class C_NEO_Player : public C_HL2MP_Player CNetworkString(m_szNeoName, MAX_PLAYER_NAME_LENGTH); CNetworkString(m_szNeoClantag, NEO_MAX_CLANTAG_LENGTH); - CNetworkString(m_szNeoCrosshair, NEO_XHAIR_SEQMAX); CNetworkVar(int, m_szNameDupePos); CNetworkVar(bool, m_bClientWantNeoName); diff --git a/src/game/server/neo/neo_player.cpp b/src/game/server/neo/neo_player.cpp index 7e04b45bc1..4f78ab2ede 100644 --- a/src/game/server/neo/neo_player.cpp +++ b/src/game/server/neo/neo_player.cpp @@ -80,7 +80,6 @@ SendPropArray(SendPropVector(SENDINFO_ARRAY(m_vLastPingByStar), -1, SPROP_COORD) SendPropInt(SENDINFO(m_NeoFlags), 4, SPROP_UNSIGNED), SendPropString(SENDINFO(m_szNeoName)), SendPropString(SENDINFO(m_szNeoClantag)), -SendPropString(SENDINFO(m_szNeoCrosshair)), SendPropInt(SENDINFO(m_szNameDupePos)), SendPropBool(SENDINFO(m_bClientWantNeoName)), @@ -119,7 +118,6 @@ DEFINE_FIELD(m_NeoFlags, FIELD_CHARACTER), DEFINE_FIELD(m_szNeoName, FIELD_STRING), DEFINE_FIELD(m_szNeoClantag, FIELD_STRING), -DEFINE_FIELD(m_szNeoCrosshair, FIELD_STRING), DEFINE_FIELD(m_szNameDupePos, FIELD_INTEGER), DEFINE_FIELD(m_bClientWantNeoName, FIELD_BOOLEAN), @@ -582,7 +580,6 @@ CNEO_Player::CNEO_Player() V_memset(m_szNeoName.GetForModify(), 0, sizeof(m_szNeoName)); m_bNeoNameHasSet = false; V_memset(m_szNeoClantag.GetForModify(), 0, sizeof(m_szNeoClantag)); - V_memset(m_szNeoCrosshair.GetForModify(), 0, sizeof(m_szNeoCrosshair)); m_bInThermOpticCamo = m_bInVision = false; m_bHasBeenAirborneForTooLongToSuperJump = false; diff --git a/src/game/server/neo/neo_player.h b/src/game/server/neo/neo_player.h index f14d0b5439..9daba26002 100644 --- a/src/game/server/neo/neo_player.h +++ b/src/game/server/neo/neo_player.h @@ -312,7 +312,7 @@ class CNEO_Player : public CHL2MP_Player CNetworkVar(unsigned char, m_NeoFlags); CNetworkString(m_szNeoName, MAX_PLAYER_NAME_LENGTH); CNetworkString(m_szNeoClantag, NEO_MAX_CLANTAG_LENGTH); - CNetworkString(m_szNeoCrosshair, NEO_XHAIR_SEQMAX); + char m_szNeoCrosshair[NEO_XHAIR_SEQMAX] = {}; CNetworkVar(int, m_szNameDupePos); // NEO NOTE (nullsystem): As dumb as client sets -> server -> client it may sound, diff --git a/src/game/server/player_resource.cpp b/src/game/server/player_resource.cpp index 8031f7eef6..f1ee368ff5 100644 --- a/src/game/server/player_resource.cpp +++ b/src/game/server/player_resource.cpp @@ -186,11 +186,10 @@ void CPlayerResource::UpdatePlayerData( void ) m_iNeoNameDupeIdx.Set(i, neoPlayer->NameDupePos()); m_bAfk.Set(i, neoPlayer->IsAFK()); { - const char *neoCrosshair = neoPlayer->m_szNeoCrosshair.Get(); string_t strt; - if (neoCrosshair && neoCrosshair[0] != '\0') + if (neoPlayer->m_szNeoCrosshair[0] != '\0') { - strt = AllocPooledString(neoCrosshair); + strt = AllocPooledString(neoPlayer->m_szNeoCrosshair); } else { diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/neo_gamerules.cpp index b6faeae680..5e199d3fce 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/neo_gamerules.cpp @@ -3588,10 +3588,9 @@ void CNEORules::ClientSettingsChanged(CBasePlayer *pPlayer) } const char *pszClNeoCrosshair = engine->GetClientConVarValue(pNEOPlayer->entindex(), "cl_neo_crosshair"); - const char *pszOldClNeoCrosshair = pNEOPlayer->m_szNeoCrosshair.Get(); - if (V_strcmp(pszOldClNeoCrosshair, pszClNeoCrosshair) != 0) + if (V_strcmp(pNEOPlayer->m_szNeoCrosshair, pszClNeoCrosshair) != 0) { - V_strncpy(pNEOPlayer->m_szNeoCrosshair.GetForModify(), pszClNeoCrosshair, NEO_XHAIR_SEQMAX); + V_strcpy_safe(pNEOPlayer->m_szNeoCrosshair, pszClNeoCrosshair); } const char *pszName = pszSteamName; From f8f5bbd1d70574fefedad698a283e2e2b4b2bd5e Mon Sep 17 00:00:00 2001 From: nullsystem <15316579+nullsystem@users.noreply.github.com> Date: Thu, 13 Aug 2026 20:22:47 +0100 Subject: [PATCH 2/2] fix stale crosshair --- src/game/client/hud_crosshair.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/game/client/hud_crosshair.cpp b/src/game/client/hud_crosshair.cpp index 6497c30052..ed38c41fe3 100644 --- a/src/game/client/hud_crosshair.cpp +++ b/src/game/client/hud_crosshair.cpp @@ -518,10 +518,6 @@ void CHudCrosshair::Paint( void ) { m_flLastCheckedXHair = gpGlobals->curtime; bThisFrameRefreshCrosshair = (V_strcmp(m_szLocalStrPlayerCrosshair, pszNeoCrosshair) != 0); - if (bThisFrameRefreshCrosshair) - { - V_strcpy_safe(m_szLocalStrPlayerCrosshair, pszNeoCrosshair); - } } } } @@ -533,6 +529,7 @@ void CHudCrosshair::Paint( void ) if (bThisFrameRefreshCrosshair) { + V_strcpy_safe(m_szLocalStrPlayerCrosshair, pszNeoCrosshair); const bool bImported = ImportCrosshair(&m_crosshairInfo, pszNeoCrosshair); if (!bImported) {