From e3911f5f9b5e46fef5c8fc5777cde56530f9170e Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 14:00:21 -0500 Subject: [PATCH 01/12] perf: remove SinCos table it's only being used by a single effect. this is slower, worse for cache, and less accurate than using the builtins. why software emulate a table? to ensure backwards compat, i kept the functions and just redirected them to the function calls. but i did remove the constants, if anyone used these I don't think they can/should be helped Co-authored-by: mastercoms --- src/game/client/c_smokestack.cpp | 2 +- src/mathlib/mathlib_base.cpp | 10 ---------- src/public/mathlib/mathlib.h | 24 ++---------------------- 3 files changed, 3 insertions(+), 33 deletions(-) diff --git a/src/game/client/c_smokestack.cpp b/src/game/client/c_smokestack.cpp index c2c0a9f0d36..7d2eac62d31 100644 --- a/src/game/client/c_smokestack.cpp +++ b/src/game/client/c_smokestack.cpp @@ -406,7 +406,7 @@ void C_SmokeStack::RenderParticles( CParticleRenderIterator *pIterator ) // makes it get translucent and fade out for a longer time. //float alpha = cosf( -M_PI_F + tLifetime * M_PI_F * 2.f ) * 0.5f + 0.5f; float tLifetime = pParticle->m_Lifetime * m_InvLifetime; - float alpha = TableCos( -M_PI_F + tLifetime * M_PI_F * 2.f ) * 0.5f + 0.5f; + float alpha = FastCos( -M_PI_F + tLifetime * M_PI_F * 2.f ) * 0.5f + 0.5f; if( tLifetime > 0.5f ) alpha *= alpha; diff --git a/src/mathlib/mathlib_base.cpp b/src/mathlib/mathlib_base.cpp index 61d67797808..8a8ef75f338 100644 --- a/src/mathlib/mathlib_base.cpp +++ b/src/mathlib/mathlib_base.cpp @@ -115,15 +115,6 @@ float (*pfInvRSquared)(const float* v) = _InvRSquared; void (*pfFastSinCos)(float x, float* s, float* c) = SinCos; float (*pfFastCos)(float x) = cosf; -float SinCosTable[SIN_TABLE_SIZE]; -void InitSinCosTable() -{ - for( int i = 0; i < SIN_TABLE_SIZE; i++ ) - { - SinCosTable[i] = sin(i * 2.0 * M_PI / SIN_TABLE_SIZE); - } -} - qboolean VectorsEqual( const float *v1, const float *v2 ) { Assert( s_bMathlibInitialized ); @@ -3402,7 +3393,6 @@ void MathLib_Init( float gamma, float texGamma, float brightness, int overbright s_bMathlibInitialized = true; - InitSinCosTable(); BuildGammaTable( gamma, texGamma, brightness, overbright ); } diff --git a/src/public/mathlib/mathlib.h b/src/public/mathlib/mathlib.h index 01107d1995f..f85c225ada7 100644 --- a/src/public/mathlib/mathlib.h +++ b/src/public/mathlib/mathlib.h @@ -436,34 +436,14 @@ inline vec_t RoundInt (vec_t in) int Q_log2(int val); -#define SIN_TABLE_SIZE 256 -#define FTOIBIAS 12582912.f -extern float SinCosTable[SIN_TABLE_SIZE]; - inline float TableCos( float theta ) { - union - { - int i; - float f; - } ftmp; - - // ideally, the following should compile down to: theta * constant + constant, changing any of these constants from defines sometimes fubars this. - ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + ( FTOIBIAS + ( SIN_TABLE_SIZE / 4 ) ); - return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ]; + return FastCos( theta ); } inline float TableSin( float theta ) { - union - { - int i; - float f; - } ftmp; - - // ideally, the following should compile down to: theta * constant + constant - ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + FTOIBIAS; - return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ]; + return sinf( theta ); } template From addac8c6e41601ed5e822c0a692d03437c41063d Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 14:13:01 -0500 Subject: [PATCH 02/12] perf: use static ConVarRefs during relatively hot functions instead of doing a O(n) lookup per frame in some cases, we can just init the ConVarRef once these ones are just possible during runtime or called relatively more compared to other non-static ConVarRefs there is one in R_LoadSkys for skyname as well, but not sure if that was fixed or not Co-authored-by: mastercoms --- src/game/client/in_steamcontroller.cpp | 4 ++-- src/game/client/tf/tf_hud_notification_panel.cpp | 4 ++-- src/game/shared/achievementmgr.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/game/client/in_steamcontroller.cpp b/src/game/client/in_steamcontroller.cpp index 62527970a0d..c70a1569139 100644 --- a/src/game/client/in_steamcontroller.cpp +++ b/src/game/client/in_steamcontroller.cpp @@ -69,8 +69,8 @@ void CInput::ApplySteamControllerCameraMove( QAngle& viewangles, CUserCmd *cmd, //roll the view angles so roll is 0 (the HL2 assumed state) and mouse adjustments are relative to the screen. //Assuming roll is unchanging, we want mouse left to translate to screen left at all times (same for right, up, and down) - ConVarRef cl_pitchdown ( "cl_pitchdown" ); - ConVarRef cl_pitchup ( "cl_pitchup" ); + static ConVarRef cl_pitchdown ( "cl_pitchdown" ); + static ConVarRef cl_pitchup ( "cl_pitchup" ); // Scale yaw and pitch inputs by sensitivity, and make sure they are within acceptable limits (important to avoid exploits, e.g. during Demoman charge we must restrict allowed yaw). float yaw = CAM_CapYaw( sc_yaw_sensitivity.GetFloat() * vecPosition.x ); diff --git a/src/game/client/tf/tf_hud_notification_panel.cpp b/src/game/client/tf/tf_hud_notification_panel.cpp index 26333fe5a5a..487282eed8a 100644 --- a/src/game/client/tf/tf_hud_notification_panel.cpp +++ b/src/game/client/tf/tf_hud_notification_panel.cpp @@ -101,7 +101,7 @@ void CHudNotificationPanel::MsgFunc_HudNotify( bf_read &msg ) // Ignore notifications in minmode if ( !bForceShow ) { - ConVarRef cl_hud_minmode( "cl_hud_minmode", true ); + static ConVarRef cl_hud_minmode( "cl_hud_minmode", true ); if ( cl_hud_minmode.IsValid() && cl_hud_minmode.GetBool() ) return; } @@ -140,7 +140,7 @@ void CHudNotificationPanel::MsgFunc_HudNotify( bf_read &msg ) void CHudNotificationPanel::MsgFunc_HudNotifyCustom( bf_read &msg ) { // Ignore notifications in minmode - ConVarRef cl_hud_minmode( "cl_hud_minmode", true ); + static ConVarRef cl_hud_minmode( "cl_hud_minmode", true ); if ( cl_hud_minmode.IsValid() && cl_hud_minmode.GetBool() ) return; diff --git a/src/game/shared/achievementmgr.cpp b/src/game/shared/achievementmgr.cpp index efa558422b6..d36af88a0db 100644 --- a/src/game/shared/achievementmgr.cpp +++ b/src/game/shared/achievementmgr.cpp @@ -1087,7 +1087,7 @@ bool CAchievementMgr::CheckAchievementsEnabled() return false; } - ConVarRef tf_bot_offline_practice( "tf_bot_offline_practice" ); + static ConVarRef tf_bot_offline_practice( "tf_bot_offline_practice" ); // no achievements for offline practice if ( tf_bot_offline_practice.GetInt() != 0 ) { From b18fd3f21ed02e397e3fc5348f10ae2da69f24cf Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 14:19:44 -0500 Subject: [PATCH 03/12] fix: backport glow inaccuracy fix Co-authored-by: mastercoms --- src/game/client/glow_overlay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/client/glow_overlay.cpp b/src/game/client/glow_overlay.cpp index 7edecd8f0c0..9cc12ddc031 100644 --- a/src/game/client/glow_overlay.cpp +++ b/src/game/client/glow_overlay.cpp @@ -159,7 +159,7 @@ void CGlowOverlay::UpdateSkyGlowObstruction( float zFar, bool bCacheFullSceneSta if ( PixelVisibility_IsAvailable() ) { // Trace a ray at the object. - Vector pos = CurrentViewOrigin() + m_vDirection * zFar * 0.999f; + Vector pos = CurrentViewOrigin() + m_vDirection * zFar * 0.99f; // UNDONE: Can probably do only the pixelvis query in this case if you can figure out where // to put it - or save the position of this trace From c78f5b8bbc7f5e35db024113c29254d061138609 Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 14:27:30 -0500 Subject: [PATCH 04/12] perf: enable rate limiting water bullet impact effects Co-authored-by: mastercoms --- src/game/shared/tf/tf_player_shared.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/shared/tf/tf_player_shared.cpp b/src/game/shared/tf/tf_player_shared.cpp index abe67cf9c09..3887a082997 100644 --- a/src/game/shared/tf/tf_player_shared.cpp +++ b/src/game/shared/tf/tf_player_shared.cpp @@ -10516,8 +10516,8 @@ void CTFPlayer::FireBullet( CTFWeaponBase *pWpn, const FireBulletsInfo_t &info, } #ifdef CLIENT_DLL -static ConVar tf_impactwatertimeenable( "tf_impactwatertimeenable", "0", FCVAR_CHEAT, "Draw impact debris effects." ); -static ConVar tf_impactwatertime( "tf_impactwatertime", "1.0f", FCVAR_CHEAT, "Draw impact debris effects." ); +static ConVar tf_impactwatertimeenable( "tf_impactwatertimeenable", "1", FCVAR_ARCHIVE, "Rate limit bullet impact effects on water." ); +static ConVar tf_impactwatertime( "tf_impactwatertime", "0.2f", FCVAR_ARCHIVE, "The interval between bullet impact effects on water." ); #endif //----------------------------------------------------------------------------- From afdc53bd3ff8504fbb7929cf39976f1e82300487 Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:24:10 -0500 Subject: [PATCH 05/12] perf: backport CalcBones optimizations from Alien Swarm * lower LODs are now marked as set up * align parent transform matrix Co-authored-by: mastercoms --- src/game/client/c_baseanimating.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/game/client/c_baseanimating.cpp b/src/game/client/c_baseanimating.cpp index 060c9409720..1437e4fa561 100644 --- a/src/game/client/c_baseanimating.cpp +++ b/src/game/client/c_baseanimating.cpp @@ -3122,6 +3122,23 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i } } + // If we're setting up LOD N, we have set up all lower LODs also + // because lower LODs always use subsets of the bones of higher LODs. + int nLOD = 0; + int nMask = BONE_USED_BY_VERTEX_LOD0; + + for ( ; nLOD < MAX_NUM_LODS; ++nLOD, nMask <<= 1 ) + { + if ( boneMask & nMask ) + break; + } + + for ( ; nLOD < MAX_NUM_LODS; ++nLOD, nMask <<= 1 ) + { + boneMask |= nMask; + } + + #ifdef DEBUG_BONE_SETUP_THREADING if ( cl_warn_thread_contested_bone_setup.GetBool() ) { @@ -3189,7 +3206,7 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i return false; // Setup our transform based on render angles and origin. - matrix3x4_t parentTransform; + ALIGN16 matrix3x4_t parentTransform ALIGN16_POST; AngleMatrix( GetRenderAngles(), GetRenderOrigin(), parentTransform ); // Load the boneMask with the total of what was asked for last frame. From e233a91b795366d5ead49955cfdb37155df23b5f Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:26:42 -0500 Subject: [PATCH 06/12] perf: add animation attachment deferral this skips a pre-mature/extra bone setup during particle simulation and flexing by allowing for the last frame's attachment position to be used technically this is a bit of a hack but it works well from my analysis. it gets rid of almost all of the particle cost in team fights besides sprite rendering Co-authored-by: mastercoms --- src/game/client/c_baseanimating.cpp | 34 +++++++++++++++++++++--- src/game/client/c_baseanimating.h | 1 + src/game/client/c_baseflex.cpp | 2 +- src/game/client/tf/c_tf_player.cpp | 14 ++++++++++ src/game/client/tf/c_tf_player.h | 1 + src/game/shared/baseviewmodel_shared.cpp | 9 +++++++ src/game/shared/baseviewmodel_shared.h | 1 + src/game/shared/econ/econ_entity.cpp | 8 ++++++ src/game/shared/econ/econ_entity.h | 1 + src/game/shared/particle_property.cpp | 4 +-- src/game/shared/tf/tf_item_inventory.cpp | 2 +- 11 files changed, 69 insertions(+), 8 deletions(-) diff --git a/src/game/client/c_baseanimating.cpp b/src/game/client/c_baseanimating.cpp index 1437e4fa561..c1c779baa14 100644 --- a/src/game/client/c_baseanimating.cpp +++ b/src/game/client/c_baseanimating.cpp @@ -1216,6 +1216,9 @@ CStudioHdr *C_BaseAnimating::OnNewModel() } m_BoneAccessor.Init( this, m_CachedBoneData.Base() ); // Always call this in case the studiohdr_t has changed. + // Reset the accumulated bone mask. + m_iAccumulatedBoneMask = 0; + // Free any IK data if (m_pIk) { @@ -2286,16 +2289,24 @@ bool C_BaseAnimating::PutAttachment( int number, const matrix3x4_t &attachmentTo return false; CAttachmentData *pAtt = &m_Attachments[number-1]; - if ( gpGlobals->frametime > 0 && pAtt->m_nLastFramecount > 0 && pAtt->m_nLastFramecount == gpGlobals->framecount - 1 ) + if ( gpGlobals->frametime > 0 && pAtt->m_nLastFramecount > 0 && pAtt->m_nLastFramecount < gpGlobals->framecount ) { Vector vecPreviousOrigin, vecOrigin; MatrixPosition( pAtt->m_AttachmentToWorld, vecPreviousOrigin ); MatrixPosition( attachmentToWorld, vecOrigin ); - pAtt->m_vOriginVelocity = (vecOrigin - vecPreviousOrigin) / gpGlobals->frametime; + + // compensate for the fact that the previous origin could have been multiple frames behind + pAtt->m_vOriginVelocity = (vecOrigin - vecPreviousOrigin) / (gpGlobals->frametime * (gpGlobals->framecount - pAtt->m_nLastFramecount)); + // only update the frame count if the position changed, so we don't have to recompute attachments + if ( !pAtt->m_vOriginVelocity.IsZero( 0.00001f ) ) + { + pAtt->m_nLastFramecount = gpGlobals->framecount; + } } else { pAtt->m_vOriginVelocity.Init(); + pAtt->m_nLastFramecount = gpGlobals->framecount; } pAtt->m_nLastFramecount = gpGlobals->framecount; pAtt->m_bAnglesComputed = false; @@ -2308,6 +2319,20 @@ bool C_BaseAnimating::PutAttachment( int number, const matrix3x4_t &attachmentTo return true; } +bool C_BaseAnimating::GetAttachmentDeferred( int number, matrix3x4_t& matrix ) +{ + if ( number < 1 || number > m_Attachments.Count() ) + return false; + + // allow visual effects (eg. particles) to be a frame behind bone setup so that there are not messy dependencies. + CAttachmentData* pAtt = &m_Attachments[number - 1]; + const bool bShouldUpdate = pAtt->m_nLastFramecount < gpGlobals->framecount - 1; + if ( bShouldUpdate && !CalcAttachments() ) + return false; + + matrix = pAtt->m_AttachmentToWorld; + return true; +} bool C_BaseAnimating::SetupBones_AttachmentHelper( CStudioHdr *hdr ) { @@ -3138,7 +3163,6 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i boneMask |= nMask; } - #ifdef DEBUG_BONE_SETUP_THREADING if ( cl_warn_thread_contested_bone_setup.GetBool() ) { @@ -3171,7 +3195,9 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i m_flLastBoneSetupTime = currentTime; } m_iPrevBoneMask = m_iAccumulatedBoneMask; - m_iAccumulatedBoneMask = 0; + + // Keep record of the fact that we've used attachments. Because of deferred attachments, we can't keep track from the previous frame. + m_iAccumulatedBoneMask = m_iAccumulatedBoneMask & BONE_USED_BY_ATTACHMENT; #ifdef STUDIO_ENABLE_PERF_COUNTERS CStudioHdr *hdr = GetModelPtr(); diff --git a/src/game/client/c_baseanimating.h b/src/game/client/c_baseanimating.h index 5b25100933c..927ebd5875d 100644 --- a/src/game/client/c_baseanimating.h +++ b/src/game/client/c_baseanimating.h @@ -278,6 +278,7 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback // Attachments. bool GetAttachment( const char *szName, Vector &absOrigin ); bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles ); + virtual bool GetAttachmentDeferred( int number, matrix3x4_t& matrix ); // Inherited from C_BaseEntity virtual bool GetAttachment( int number, Vector &origin ); diff --git a/src/game/client/c_baseflex.cpp b/src/game/client/c_baseflex.cpp index b63e43a1019..1fbe86cb839 100644 --- a/src/game/client/c_baseflex.cpp +++ b/src/game/client/c_baseflex.cpp @@ -574,7 +574,7 @@ Vector C_BaseFlex::SetViewTarget( CStudioHdr *pStudioHdr ) if (m_iEyeAttachment > 0) { matrix3x4_t attToWorld; - if (!GetAttachment( m_iEyeAttachment, attToWorld )) + if (!GetAttachmentDeferred( m_iEyeAttachment, attToWorld )) { return Vector( 0, 0, 0); } diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index 73d464cc810..720ef47bb61 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -1329,6 +1329,20 @@ bool C_TFRagdoll::GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld } } +bool C_TFRagdoll::GetAttachmentDeferred( int iAttachment, matrix3x4_t& attachmentToWorld ) +{ + int iHeadAttachment = LookupAttachment( "head" ); + if ( IsDecapitation() && (iAttachment == iHeadAttachment) ) + { + MatrixCopy( m_mHeadAttachment, attachmentToWorld ); + return true; + } + else + { + return BaseClass::GetAttachmentDeferred( iAttachment, attachmentToWorld ); + } +} + //----------------------------------------------------------------------------- // Purpose: // Input : - diff --git a/src/game/client/tf/c_tf_player.h b/src/game/client/tf/c_tf_player.h index 0fcee373088..c9520ed29e3 100644 --- a/src/game/client/tf/c_tf_player.h +++ b/src/game/client/tf/c_tf_player.h @@ -1054,6 +1054,7 @@ class C_TFRagdoll : public C_BaseFlex int GetDamageCustom() { return m_iDamageCustom; } virtual bool GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld ); + virtual bool GetAttachmentDeferred( int iAttachment, matrix3x4_t& attachmentToWorld ); int GetClass() { return m_iClass; } diff --git a/src/game/shared/baseviewmodel_shared.cpp b/src/game/shared/baseviewmodel_shared.cpp index 3b2d06f326f..fbcbd464a40 100644 --- a/src/game/shared/baseviewmodel_shared.cpp +++ b/src/game/shared/baseviewmodel_shared.cpp @@ -727,6 +727,15 @@ bool CBaseViewModel::GetAttachment( int number, matrix3x4_t &matrix ) return BaseClass::GetAttachment( number, matrix ); } +bool C_BaseViewModel::GetAttachmentDeferred( int number, matrix3x4_t& matrix ) +{ + // Update priority for your own viewmodel (no deferral) + if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() ) + return m_hWeapon.Get()->GetAttachment( number, matrix ); + + return BaseClass::GetAttachment( number, matrix ); +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/src/game/shared/baseviewmodel_shared.h b/src/game/shared/baseviewmodel_shared.h index 5f1450e614e..6ed11873712 100644 --- a/src/game/shared/baseviewmodel_shared.h +++ b/src/game/shared/baseviewmodel_shared.h @@ -172,6 +172,7 @@ class CBaseViewModel : public CBaseAnimating, public IHasOwner // Attachments virtual int LookupAttachment( const char *pAttachmentName ); virtual bool GetAttachment( int number, matrix3x4_t &matrix ); + virtual bool GetAttachmentDeferred( int number, matrix3x4_t& matrix ); virtual bool GetAttachment( int number, Vector &origin ); virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); diff --git a/src/game/shared/econ/econ_entity.cpp b/src/game/shared/econ/econ_entity.cpp index dd48f4c41ae..90f8c864883 100644 --- a/src/game/shared/econ/econ_entity.cpp +++ b/src/game/shared/econ/econ_entity.cpp @@ -1983,6 +1983,14 @@ bool CEconEntity::GetAttachment( int number, matrix3x4_t &matrix ) return BaseClass::GetAttachment( number, matrix ); } +bool C_EconEntity::GetAttachmentDeferred( int number, matrix3x4_t& matrix ) +{ + if ( m_hViewmodelAttachment ) + return m_hViewmodelAttachment->GetAttachmentDeferred( number, matrix ); + + return BaseClass::GetAttachmentDeferred( number, matrix ); +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/src/game/shared/econ/econ_entity.h b/src/game/shared/econ/econ_entity.h index 5e5139fae31..de92ef7d5ac 100644 --- a/src/game/shared/econ/econ_entity.h +++ b/src/game/shared/econ/econ_entity.h @@ -117,6 +117,7 @@ class CEconEntity : public CBaseAnimating, public IHasAttributes virtual bool GetAttachment( const char *szName, Vector &absOrigin ) { return BaseClass::GetAttachment(szName,absOrigin); } virtual bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles ) { return BaseClass::GetAttachment(szName,absOrigin,absAngles); } virtual bool GetAttachment( int number, matrix3x4_t &matrix ); + virtual bool GetAttachmentDeferred( int number, matrix3x4_t& matrix ); virtual bool GetAttachment( int number, Vector &origin ); virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); diff --git a/src/game/shared/particle_property.cpp b/src/game/shared/particle_property.cpp index dc2f46c9462..780463157b3 100644 --- a/src/game/shared/particle_property.cpp +++ b/src/game/shared/particle_property.cpp @@ -605,10 +605,10 @@ void CParticleProperty::UpdateControlPoint( ParticleEffectList_t *pEffect, int i { matrix3x4_t attachmentToWorld; - if ( !pAnimating->GetAttachment( pPoint->iAttachmentPoint, attachmentToWorld ) ) + if ( !pAnimating->GetAttachmentDeferred( pPoint->iAttachmentPoint, attachmentToWorld ) ) { // try C_BaseAnimating if attach point is not on the weapon - if ( !pAnimating->C_BaseAnimating::GetAttachment( pPoint->iAttachmentPoint, attachmentToWorld ) ) + if ( !pAnimating->C_BaseAnimating::GetAttachmentDeferred( pPoint->iAttachmentPoint, attachmentToWorld ) ) { Warning( "Cannot update control point %d for effect '%s'.\n", pPoint->iAttachmentPoint, pEffect->pParticleEffect->GetEffectName() ); // Remove the effect cause this warning means something is orphaned diff --git a/src/game/shared/tf/tf_item_inventory.cpp b/src/game/shared/tf/tf_item_inventory.cpp index a3711145980..de0a0935e10 100644 --- a/src/game/shared/tf/tf_item_inventory.cpp +++ b/src/game/shared/tf/tf_item_inventory.cpp @@ -964,7 +964,7 @@ void CTFPlayerInventory::LoadLocalLoadout() m_LoadoutItems[iClass][iSlot] = uItemId; CEconItemView *pItem = GetInventoryItemByItemID(uItemId); - if (pItem) { + if ( pItem && pItem->GetSOCData() ) { pItem->GetSOCData()->Equip(iClass, iSlot); } } From 0062a261df0829ec28920a445f8bb5f31155cf83 Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:33:07 -0500 Subject: [PATCH 07/12] perf: re-enable water LOD on all platforms, not just x360 cheap water LOD was disabled with local specular due to shipping constraints but re-enabled for ep2 on xbox 360 this change now re-enables it for all platforms Co-authored-by: mastercoms --- src/game/client/viewrender.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/game/client/viewrender.cpp b/src/game/client/viewrender.cpp index e49f44595d4..b9fba9f8a07 100644 --- a/src/game/client/viewrender.cpp +++ b/src/game/client/viewrender.cpp @@ -2796,15 +2796,11 @@ void CViewRender::DetermineWaterRenderInfo( const VisibleFogVolumeInfo_t &fogVol // Gary says: I'm reverting this change so that water LOD works on dx9 for ep2. // Check if the water is out of the cheap water LOD range; if so, use cheap water -#ifdef _X360 if ( !bForceExpensive && ( bForceCheap || ( fogVolumeInfo.m_flDistanceToWater >= m_flCheapWaterEndDistance ) ) ) { return; } -#else - if ( ( (fogVolumeInfo.m_flDistanceToWater >= m_flCheapWaterEndDistance) && !bLocalReflection ) || bForceCheap ) - return; -#endif + // Get the material that is for the water surface that is visible and check to see // what render targets need to be rendered, if any. if ( !r_WaterDrawRefraction.GetBool() ) From 646768dd368e479a8f5a8aaef8acf34da246855f Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:34:56 -0500 Subject: [PATCH 08/12] perf: ensure class menu model rendering only when open some players report that they have tracked down some cases where the player model could still update its rendering outside the class menu this is commonly observed through FPS increasing when using the scoreboard may only be relevant for some custom HUDs Co-authored-by: mastercoms --- src/game/client/tf/vgui/tf_classmenu.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/game/client/tf/vgui/tf_classmenu.cpp b/src/game/client/tf/vgui/tf_classmenu.cpp index 3fd7eb04065..af494064785 100644 --- a/src/game/client/tf/vgui/tf_classmenu.cpp +++ b/src/game/client/tf/vgui/tf_classmenu.cpp @@ -1179,6 +1179,11 @@ void CTFClassMenu::SetVisible( bool state ) if ( state ) { + if (m_pTFPlayerModelPanel) + { + m_pTFPlayerModelPanel->SetVisible( true ); + } + engine->ServerCmd( "menuopen" ); // to the server engine->ClientCmd( "_cl_classmenuopen 1" ); // for other panels CBroadcastRecipientFilter filter; @@ -1198,6 +1203,11 @@ void CTFClassMenu::SetVisible( bool state ) { engine->ServerCmd( "menuclosed" ); engine->ClientCmd( "_cl_classmenuopen 0" ); + + if (m_pTFPlayerModelPanel) + { + m_pTFPlayerModelPanel->SetVisible( false ); + } if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) { From 37220112691450b12af67bb83fa697a4446b66f6 Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:41:28 -0500 Subject: [PATCH 09/12] perf: fix inconsistencies with ragdoll settings g_ragdoll_fadespeed was not being used in TF2 ragdolls despite being used in other games fix cl_ragdoll_forcefade not working on the same frame if delay is 0 fix cosmetics not respecting ragdoll fade settings Co-authored-by: mastercoms --- src/game/client/tf/c_tf_player.cpp | 37 ++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index 720ef47bb61..634883a6640 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -1383,6 +1383,9 @@ bool C_TFRagdoll::IsRagdollVisible() #define DISSOLVE_FADE_OUT_START_TIME 2.0f #define DISSOLVE_FADE_OUT_END_TIME 2.0f +extern ConVar g_ragdoll_lvfadespeed; +extern ConVar g_ragdoll_fadespeed; + void C_TFRagdoll::ClientThink( void ) { SetNextClientThink( CLIENT_THINK_ALWAYS ); @@ -1524,9 +1527,16 @@ void C_TFRagdoll::ClientThink( void ) if ( m_bFadingOut == true ) { int iAlpha = GetRenderColor().a; - int iFadeSpeed = 600.0f; + int iFadeSpeed = ( g_RagdollLVManager.IsLowViolence() ) ? g_ragdoll_lvfadespeed.GetInt() : g_ragdoll_fadespeed.GetInt(); - iAlpha = MAX( iAlpha - ( iFadeSpeed * gpGlobals->frametime ), 0 ); + if (iFadeSpeed < 1) + { + iAlpha = 0; + } + else + { + iAlpha = MAX( iAlpha - ( iFadeSpeed * gpGlobals->frametime ), 0 ); + } SetRenderMode( kRenderTransAlpha ); SetRenderColorA( iAlpha ); @@ -1545,15 +1555,22 @@ void C_TFRagdoll::ClientThink( void ) if ( cl_ragdoll_forcefade.GetBool() ) { m_bFadingOut = true; - float flDelay = cl_ragdoll_fade_time.GetFloat() * 0.33f; - m_fDeathTime = gpGlobals->curtime + flDelay; - RemoveAllDecals(); - } - // Fade out after the specified delay. - StartFadeOut( cl_ragdoll_fade_time.GetFloat() * 0.33f ); - return; + float flDelay = cl_ragdoll_fade_time.GetFloat() * 0.33f; + if (flDelay > 0.01f) + { + m_fDeathTime = gpGlobals->curtime + flDelay; + return; + } + m_fDeathTime = -1; + } + else + { + // Fade out after the specified delay. + StartFadeOut( cl_ragdoll_fade_time.GetFloat() * 0.33f ); + return; + } } // Remove us if our death time has passed. @@ -7518,7 +7535,7 @@ void C_TFPlayer::DropWearable( C_TFWearable *pItem, const breakablepropparams_t } pEntity->m_nSkin = m_nSkin; - pEntity->StartFadeOut( 15.0f ); + pEntity->StartFadeOut( cl_ragdoll_fade_time.GetFloat() ); IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject(); if ( !pPhysicsObject ) From 5238d244bb2a3c4b43c2ea8d494f4952110c7c56 Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:46:40 -0500 Subject: [PATCH 10/12] perf: add DX8 effects to mat_reducefillrate despite being a less efficient renderer, DX8 is still used for performance reasons due to its lower quality settings. we can continue to provide these lower quality settings with the much more robust and efficient DX9 renderer, which will benefit the playerbase and game. engine change: mastercomfig/tf2-patches-old@eaac092#diff-260f8c14c7dd12646fa64721dcdf647450005b5002ce33047bc6a9ccb578daac Co-authored-by: mastercoms --- src/game/client/tf/c_tf_player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index 634883a6640..f90764406c5 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -6876,7 +6876,7 @@ int C_TFPlayer::DrawModel( int flags ) // Don't draw the model at all if we're fully invisible if ( GetEffectiveInvisibilityLevel() >= 1.0f ) { - if ( m_hHalloweenBombHat && ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 90 ) && !m_hHalloweenBombHat->IsEffectActive( EF_NODRAW ) ) + if ( m_hHalloweenBombHat && ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 90 || g_pMaterialSystemHardwareConfig->PreferReducedFillrate() ) && !m_hHalloweenBombHat->IsEffectActive( EF_NODRAW ) ) { m_hHalloweenBombHat->SetEffects( EF_NODRAW ); } @@ -6884,7 +6884,7 @@ int C_TFPlayer::DrawModel( int flags ) } else { - if ( m_hHalloweenBombHat && ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 90 ) && m_hHalloweenBombHat->IsEffectActive( EF_NODRAW ) ) + if ( m_hHalloweenBombHat && ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 90 || g_pMaterialSystemHardwareConfig->PreferReducedFillrate() ) && m_hHalloweenBombHat->IsEffectActive( EF_NODRAW ) ) { m_hHalloweenBombHat->RemoveEffects( EF_NODRAW ); } From fcfd6a23e07c6914af055bffa008270723d88890 Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:54:44 -0500 Subject: [PATCH 11/12] perf: update ceil and floor to int functions Co-authored-by: mastercoms --- src/public/mathlib/mathlib.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/public/mathlib/mathlib.h b/src/public/mathlib/mathlib.h index f85c225ada7..d7146fa83d1 100644 --- a/src/public/mathlib/mathlib.h +++ b/src/public/mathlib/mathlib.h @@ -1262,11 +1262,17 @@ inline int Floor2Int( float a ) { int RetVal; #if defined( PLATFORM_INTEL ) + +#if MAPBASE + RetVal = _mm_cvt_ss2si(_mm_set_ss(a + a - 0.5f)) >> 1; +#else // Convert to int and back, compare, subtract one if too big __m128 a128 = _mm_set_ss(a); RetVal = _mm_cvtss_si32(a128); __m128 rounded128 = _mm_cvt_si2ss(_mm_setzero_ps(), RetVal); RetVal -= _mm_comigt_ss( rounded128, a128 ); +#endif // MAPBASE + #else RetVal = static_cast( floor(a) ); #endif @@ -1319,11 +1325,17 @@ inline int Ceil2Int( float a ) { int RetVal; #if defined( PLATFORM_INTEL ) - // Convert to int and back, compare, add one if too small + +#if MAPBASE + RetVal = -(_mm_cvt_ss2si(_mm_set_ss(-0.5f - (a + a))) >> 1); +#else + // Convert to int and back, compare, add one if too small __m128 a128 = _mm_load_ss(&a); RetVal = _mm_cvtss_si32(a128); __m128 rounded128 = _mm_cvt_si2ss(_mm_setzero_ps(), RetVal); RetVal += _mm_comilt_ss( rounded128, a128 ); +#endif // MAPBASE + #else RetVal = static_cast( ceil(a) ); #endif From f6f5e9f845d4a12ea856a0d8a78e09c25bb7a019 Mon Sep 17 00:00:00 2001 From: kity <58897393+cattslmao@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:04:52 -0500 Subject: [PATCH 12/12] fix(gameplay): fix usages of ceil instead of Ceil2Int this fixes platform inconsistencies between Linux and Windows on certain floating point values. for example, on Windows servers, small ammo packs will grant 41 metal when on Linux servers they provide the intended 40 metal. Ceil2Int is also faster computationally Co-authored-by: mastercoms --- src/game/server/tf/entity_ammopack.cpp | 8 ++++---- src/game/server/tf/entity_healthkit.cpp | 12 ++++++------ src/game/server/tf/tf_ammo_pack.cpp | 6 +++--- src/game/server/tf/tf_obj.cpp | 4 ++-- src/game/server/tf/tf_obj_teleporter.cpp | 2 +- src/game/server/tf/tf_player.cpp | 4 ++-- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/game/server/tf/entity_ammopack.cpp b/src/game/server/tf/entity_ammopack.cpp index b861661ed99..0339597db3b 100644 --- a/src/game/server/tf/entity_ammopack.cpp +++ b/src/game/server/tf/entity_ammopack.cpp @@ -66,19 +66,19 @@ bool CAmmoPack::MyTouch( CBasePlayer *pPlayer ) float flPackRatio = PackRatios[GetPowerupSize()]; int iMaxPrimary = pTFPlayer->GetMaxAmmo(TF_AMMO_PRIMARY); - if ( pTFPlayer->GiveAmmo( ceil(iMaxPrimary * flPackRatio), TF_AMMO_PRIMARY, true, kAmmoSource_Pickup ) ) + if ( pTFPlayer->GiveAmmo( Ceil2Int(iMaxPrimary * flPackRatio), TF_AMMO_PRIMARY, true, kAmmoSource_Pickup ) ) { bSuccess = true; } int iMaxSecondary = pTFPlayer->GetMaxAmmo(TF_AMMO_SECONDARY); - if ( pTFPlayer->GiveAmmo( ceil(iMaxSecondary * flPackRatio), TF_AMMO_SECONDARY, true, kAmmoSource_Pickup ) ) + if ( pTFPlayer->GiveAmmo( Ceil2Int(iMaxSecondary * flPackRatio), TF_AMMO_SECONDARY, true, kAmmoSource_Pickup ) ) { bSuccess = true; } int iMaxMetal = pTFPlayer->GetMaxAmmo(TF_AMMO_METAL); - if ( pTFPlayer->GiveAmmo( ceil(iMaxMetal * flPackRatio), TF_AMMO_METAL, true, kAmmoSource_Pickup ) ) + if ( pTFPlayer->GiveAmmo( Ceil2Int(iMaxMetal * flPackRatio), TF_AMMO_METAL, true, kAmmoSource_Pickup ) ) { bSuccess = true; } @@ -112,7 +112,7 @@ bool CAmmoPack::MyTouch( CBasePlayer *pPlayer ) if ( pTFPlayer->IsPlayerClass( TF_CLASS_ENGINEER ) ) { int iMaxGrenades1 = pTFPlayer->GetMaxAmmo(TF_AMMO_GRENADES1); - if ( pTFPlayer->GiveAmmo( ceil(iMaxGrenades1 * flPackRatio), TF_AMMO_GRENADES1, true, kAmmoSource_Pickup ) ) + if ( pTFPlayer->GiveAmmo( Ceil2Int(iMaxGrenades1 * flPackRatio), TF_AMMO_GRENADES1, true, kAmmoSource_Pickup ) ) { bSuccess = true; } diff --git a/src/game/server/tf/entity_healthkit.cpp b/src/game/server/tf/entity_healthkit.cpp index c02121ece3a..279579f1ea6 100644 --- a/src/game/server/tf/entity_healthkit.cpp +++ b/src/game/server/tf/entity_healthkit.cpp @@ -90,7 +90,7 @@ bool CHealthKit::MyTouch( CBasePlayer *pPlayer ) { float flRuneHealthBonus = ( pTFPlayer->m_Shared.GetCarryingRuneType() != RUNE_KNOCKOUT ) ? pTFPlayer->GetRuneHealthBonus() : 0; - float flHealth = ceil( ( pPlayer->GetMaxHealth() - flRuneHealthBonus ) * PackRatios[GetPowerupSize()] ); + float flHealth = Ceil2Int( ( pPlayer->GetMaxHealth() - flRuneHealthBonus ) * PackRatios[GetPowerupSize()] ); CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pPlayer, flHealth, mult_health_frompacks ); @@ -116,7 +116,7 @@ bool CHealthKit::MyTouch( CBasePlayer *pPlayer ) { float flDisguiseHealth = pTFPlayer->m_Shared.GetDisguiseHealth(); float flDisguiseMaxHealth = pTFPlayer->m_Shared.GetDisguiseMaxHealth(); - float flHealthToAdd = ceil(flDisguiseMaxHealth * PackRatios[GetPowerupSize()]); + float flHealthToAdd = Ceil2Int(flDisguiseMaxHealth * PackRatios[GetPowerupSize()]); // don't want to add more than we're allowed to have if ( flHealthToAdd > flDisguiseMaxHealth - flDisguiseHealth ) @@ -248,19 +248,19 @@ bool CHealthAmmoKit::MyTouch( CBasePlayer *pPlayer ) float flPackRatio = PackRatios[GetPowerupSize()]; int iMaxPrimary = pTFPlayer->GetMaxAmmo( TF_AMMO_PRIMARY ); - if ( pTFPlayer->GiveAmmo( ceil( iMaxPrimary * flPackRatio ), TF_AMMO_PRIMARY, true, kAmmoSource_Pickup ) ) + if ( pTFPlayer->GiveAmmo( Ceil2Int( iMaxPrimary * flPackRatio ), TF_AMMO_PRIMARY, true, kAmmoSource_Pickup ) ) { bAmmoSuccess = true; } int iMaxSecondary = pTFPlayer->GetMaxAmmo( TF_AMMO_SECONDARY ); - if ( pTFPlayer->GiveAmmo( ceil( iMaxSecondary * flPackRatio ), TF_AMMO_SECONDARY, true, kAmmoSource_Pickup ) ) + if ( pTFPlayer->GiveAmmo( Ceil2Int( iMaxSecondary * flPackRatio ), TF_AMMO_SECONDARY, true, kAmmoSource_Pickup ) ) { bAmmoSuccess = true; } int iMaxMetal = pTFPlayer->GetMaxAmmo( TF_AMMO_METAL ); - if ( pTFPlayer->GiveAmmo( ceil( iMaxMetal * flPackRatio ), TF_AMMO_METAL, true, kAmmoSource_Pickup ) ) + if ( pTFPlayer->GiveAmmo( Ceil2Int( iMaxMetal * flPackRatio ), TF_AMMO_METAL, true, kAmmoSource_Pickup ) ) { bAmmoSuccess = true; } @@ -278,7 +278,7 @@ bool CHealthAmmoKit::MyTouch( CBasePlayer *pPlayer ) if ( pTFPlayer->IsPlayerClass( TF_CLASS_ENGINEER ) ) { int iMaxGrenades1 = pTFPlayer->GetMaxAmmo( TF_AMMO_GRENADES1 ); - if ( pTFPlayer->GiveAmmo( ceil( iMaxGrenades1 * flPackRatio ), TF_AMMO_GRENADES1, true, kAmmoSource_Pickup ) ) + if ( pTFPlayer->GiveAmmo( Ceil2Int( iMaxGrenades1 * flPackRatio ), TF_AMMO_GRENADES1, true, kAmmoSource_Pickup ) ) { bAmmoSuccess = true; } diff --git a/src/game/server/tf/tf_ammo_pack.cpp b/src/game/server/tf/tf_ammo_pack.cpp index bb355403566..7decf04154c 100644 --- a/src/game/server/tf/tf_ammo_pack.cpp +++ b/src/game/server/tf/tf_ammo_pack.cpp @@ -345,10 +345,10 @@ void CTFAmmoPack::PackTouch( CBaseEntity *pOther ) } int iMaxPrimary = pPlayer->GetMaxAmmo(TF_AMMO_PRIMARY); - GiveAmmo( ceil( iMaxPrimary * m_flAmmoRatio ), TF_AMMO_PRIMARY ); + GiveAmmo( Ceil2Int( iMaxPrimary * m_flAmmoRatio ), TF_AMMO_PRIMARY ); int iMaxSecondary = pPlayer->GetMaxAmmo(TF_AMMO_SECONDARY); - GiveAmmo( ceil( iMaxSecondary * m_flAmmoRatio ), TF_AMMO_SECONDARY ); + GiveAmmo( Ceil2Int( iMaxSecondary * m_flAmmoRatio ), TF_AMMO_SECONDARY ); int iAmmoTaken = 0; @@ -393,7 +393,7 @@ void CTFAmmoPack::PackTouch( CBaseEntity *pOther ) if ( pPlayer->IsPlayerClass( TF_CLASS_ENGINEER ) ) { int iMaxGrenades1 = pPlayer->GetMaxAmmo( TF_AMMO_GRENADES1 ); - iAmmoTaken += pPlayer->GiveAmmo( ceil(iMaxGrenades1 * m_flAmmoRatio), TF_AMMO_GRENADES1 ); + iAmmoTaken += pPlayer->GiveAmmo( Ceil2Int(iMaxGrenades1 * m_flAmmoRatio), TF_AMMO_GRENADES1 ); } if ( m_PackType == AP_HALLOWEEN ) diff --git a/src/game/server/tf/tf_obj.cpp b/src/game/server/tf/tf_obj.cpp index c7a9e93a0a2..0e03a52d87a 100644 --- a/src/game/server/tf/tf_obj.cpp +++ b/src/game/server/tf/tf_obj.cpp @@ -1604,7 +1604,7 @@ void CBaseObject::SetHealth( float flHealth ) bool changed = m_flHealth != flHealth; m_flHealth = flHealth; - m_iHealth = ceil(m_flHealth); + m_iHealth = Ceil2Int(m_flHealth); /* @@ -2946,7 +2946,7 @@ int CBaseObject::Command_Repair( CTFPlayer *pActivator, float flAmount, float fl float flRepairAmountMax = flAmount * flRepairMod; int iRepairAmount = Min( RoundFloatToInt( flRepairAmountMax ), GetMaxHealth() - RoundFloatToInt( GetHealth() ) ); - int iRepairCost = ceil( (float)( iRepairAmount ) / flRepairToMetalRatio ); + int iRepairCost = Ceil2Int( (float)( iRepairAmount ) / flRepairToMetalRatio ); if ( iRepairCost > pActivator->GetBuildResources() ) { // What can we afford? diff --git a/src/game/server/tf/tf_obj_teleporter.cpp b/src/game/server/tf/tf_obj_teleporter.cpp index 723eb88ea27..0b5f6e33994 100644 --- a/src/game/server/tf/tf_obj_teleporter.cpp +++ b/src/game/server/tf/tf_obj_teleporter.cpp @@ -690,7 +690,7 @@ int CObjectTeleporter::Command_Repair( CTFPlayer *pActivator, float flAmount, fl { float flRepairAmountMax = flAmount * flRepairMod; int iRepairAmount = Min( flRepairAmountMax, pMatch->GetMaxHealth() - pMatch->GetHealth() ); - int iRepairCost = ceil( (float)iRepairAmount / flRepairToMetalRatio ); + int iRepairCost = Ceil2Int( (float)iRepairAmount / flRepairToMetalRatio ); if ( iRepairCost > pActivator->GetBuildResources() ) { // What can we afford? diff --git a/src/game/server/tf/tf_player.cpp b/src/game/server/tf/tf_player.cpp index cc2961679c2..0ebf517f893 100644 --- a/src/game/server/tf/tf_player.cpp +++ b/src/game/server/tf/tf_player.cpp @@ -1879,7 +1879,7 @@ void CTFPlayer::RegenThink( void ) } else if ( m_flAccumulatedHealthRegen < -1.f ) { - nHealAmount = ceil( m_flAccumulatedHealthRegen ); + nHealAmount = Ceil2Int( m_flAccumulatedHealthRegen ); TakeDamage( CTakeDamageInfo( this, this, NULL, vec3_origin, WorldSpaceCenter(), nHealAmount * -1, DMG_GENERIC ) ); } @@ -2013,7 +2013,7 @@ void CTFPlayer::RuneRegenThink( void ) } else if ( m_flAccumulatedRuneHealthRegen < -1.0 ) { - nHealAmount = ceil( m_flAccumulatedRuneHealthRegen ); + nHealAmount = Ceil2Int( m_flAccumulatedRuneHealthRegen ); TakeDamage( CTakeDamageInfo( this, this, NULL, vec3_origin, WorldSpaceCenter(), nHealAmount * -1, DMG_GENERIC ) ); }