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 c2c0a9f0d3..7d2eac62d3 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 61d6779780..8a8ef75f33 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 01107d1995..f85c225ada 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 62527970a0..c70a156913 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 26333fe5a5..487282eed8 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 efa558422b..d36af88a0d 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 7edecd8f0c..9cc12ddc03 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 abe67cf9c0..3887a08299 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 060c940972..1437e4fa56 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 1437e4fa56..c1c779baa1 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 5b25100933..927ebd5875 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 b63e43a101..1fbe86cb83 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 73d464cc81..720ef47bb6 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 0fcee37308..c9520ed29e 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 3b2d06f326..fbcbd464a4 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 5f1450e614..6ed1187371 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 dd48f4c41a..90f8c86488 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 5e5139fae3..de92ef7d5a 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 dc2f46c946..780463157b 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 a371114598..de0a0935e1 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 e49f44595d..b9fba9f8a0 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 3fd7eb0406..af49406478 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 720ef47bb6..634883a664 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 634883a664..f90764406c 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 f85c225ada..d7146fa83d 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 b861661ed9..0339597db3 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 c02121ece3..279579f1ea 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 bb35540356..7decf04154 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 c7a9e93a0a..0e03a52d87 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 723eb88ea2..0b5f6e3399 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 cc2961679c..0ebf517f89 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 ) ); }