From b52e414ac3e1cae97f689069f919dd3958e51997 Mon Sep 17 00:00:00 2001 From: stephanie sappho lenzo Date: Mon, 3 Jul 2023 04:33:34 -0400 Subject: [PATCH 1/8] Run timers every tick instead of arbitrarily on 100ms thinks, adding a significantly higher amount of precision --- core/TimerSys.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 2084b153e1..8a2987f86d 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -234,13 +234,15 @@ void TimerSystem::GameFrame(bool simulating) m_fLastTickedTime = gpGlobals->curtime; m_bHasMapTickedYet = true; + RunFrame(); +/* if (g_fUniversalTime >= g_fTimerThink) { RunFrame(); g_fTimerThink = CalcNextThink(g_fTimerThink, TIMER_MIN_ACCURACY); } - +*/ RunFrameHooks(simulating); if (m_pOnGameFrame->GetFunctionCount()) From 107e00c8311d74c5976a56ca496b3484df5fa542 Mon Sep 17 00:00:00 2001 From: stephanie sappho lenzo Date: Wed, 26 Jul 2023 05:52:25 -0400 Subject: [PATCH 2/8] undo force push --- core/TimerSys.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 8a2987f86d..771ba9ca17 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -36,8 +36,6 @@ #include "ConVarManager.h" #include "logic_bridge.h" -#define TIMER_MIN_ACCURACY 0.1 - TimerSystem g_Timers; double g_fUniversalTime = 0.0f; float g_fGameStartTime = 0.0f; /* Game game start time, non-universal */ @@ -146,7 +144,7 @@ class DefaultMapTimer : */ inline double CalcNextThink(double last, float interval) { - if (g_fUniversalTime - last - interval <= TIMER_MIN_ACCURACY) + if (g_fUniversalTime - last - interval <= gpGlobals->interval_per_tick) { return last + interval; } @@ -234,15 +232,13 @@ void TimerSystem::GameFrame(bool simulating) m_fLastTickedTime = gpGlobals->curtime; m_bHasMapTickedYet = true; - RunFrame(); -/* if (g_fUniversalTime >= g_fTimerThink) { RunFrame(); - g_fTimerThink = CalcNextThink(g_fTimerThink, TIMER_MIN_ACCURACY); + g_fTimerThink = CalcNextThink(g_fTimerThink, gpGlobals->interval_per_tick); } -*/ + RunFrameHooks(simulating); if (m_pOnGameFrame->GetFunctionCount()) From 833d727a713584c526875e417b02100e9cec6507 Mon Sep 17 00:00:00 2001 From: Headline Date: Fri, 19 Sep 2025 00:15:25 -0700 Subject: [PATCH 3/8] Let's handle high precision timers separately --- core/TimerSys.cpp | 108 +++++++++++++++++++++---------------- core/TimerSys.h | 20 +++++-- plugins/include/timers.inc | 1 + public/ITimerSystem.h | 1 + 4 files changed, 80 insertions(+), 50 deletions(-) diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 771ba9ca17..f3ff5bf7a5 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -36,10 +36,12 @@ #include "ConVarManager.h" #include "logic_bridge.h" +#define TIMER_MIN_ACCURACY 0.1 + TimerSystem g_Timers; double g_fUniversalTime = 0.0f; -float g_fGameStartTime = 0.0f; /* Game game start time, non-universal */ -double g_fTimerThink = 0.0f; /* Timer's next think time */ +float g_fGameStartTime = 0.0f; /* Game game start time, non-universal */ +double g_fTimerThink = 0.0f; /* Timer's next think time */ const double *g_pUniversalTime = &g_fUniversalTime; ConVar *mp_timelimit = NULL; int g_TimeLeftMode = 0; @@ -142,9 +144,10 @@ class DefaultMapTimer : * that a drastic jump in time will continue acting normally. Users * may not expect this, but... I think it is the best solution. */ -inline double CalcNextThink(double last, float interval) +inline double CalcNextThink(double last, float interval, bool useTickInterval = false) { - if (g_fUniversalTime - last - interval <= gpGlobals->interval_per_tick) + const float intervalAccuracy = useTickInterval ? gpGlobals->interval_per_tick : TIMER_MIN_ACCURACY; + if (g_fUniversalTime - last - interval <= intervalAccuracy) { return last + interval; } @@ -163,6 +166,7 @@ void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, m_Flags = flags; m_InExec = false; m_KillMe = false; + m_HighSpeed = false; } TimerSystem::TimerSystem() @@ -232,10 +236,11 @@ void TimerSystem::GameFrame(bool simulating) m_fLastTickedTime = gpGlobals->curtime; m_bHasMapTickedYet = true; - if (g_fUniversalTime >= g_fTimerThink) - { - RunFrame(); + const bool timerThink = g_fUniversalTime >= g_fTimerThink; + RunFrame(timerThink); + if (timerThink) + { g_fTimerThink = CalcNextThink(g_fTimerThink, gpGlobals->interval_per_tick); } @@ -247,13 +252,12 @@ void TimerSystem::GameFrame(bool simulating) } } -void TimerSystem::RunFrame() +void TimerSystem::ProcessTimerType(double curtime, TimerType& timerType, bool isHighSpeed) { - ITimer *pTimer; + ITimer *pTimer; TimerIter iter; - double curtime = GetSimulatedTime(); - for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); ) + for (iter=timerType.m_SingleTimers.begin(); iter!=timerType.m_SingleTimers.end(); ) { pTimer = (*iter); if (curtime >= pTimer->m_ToExec) @@ -261,7 +265,7 @@ void TimerSystem::RunFrame() pTimer->m_InExec = true; pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - iter = m_SingleTimers.erase(iter); + iter = timerType.m_SingleTimers.erase(iter); m_FreeTimers.push(pTimer); } else @@ -271,7 +275,7 @@ void TimerSystem::RunFrame() } ResultType res; - for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); ) + for (iter=timerType.m_LoopTimers.begin(); iter!=timerType.m_LoopTimers.end(); ) { pTimer = (*iter); if (curtime >= pTimer->m_ToExec) @@ -281,17 +285,31 @@ void TimerSystem::RunFrame() if (pTimer->m_KillMe || (res == Pl_Stop)) { pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - iter = m_LoopTimers.erase(iter); + iter = timerType.m_LoopTimers.erase(iter); m_FreeTimers.push(pTimer); continue; } pTimer->m_InExec = false; - pTimer->m_ToExec = CalcNextThink(pTimer->m_ToExec, pTimer->m_Interval); + pTimer->m_ToExec = CalcNextThink(pTimer->m_ToExec, pTimer->m_Interval, isHighSpeed); } iter++; } } +void TimerSystem::RunFrame(bool timerThink) +{ + const double curtime = GetSimulatedTime(); + + // Most timers do not need to be updated every frame + if (timerThink) + { + ProcessTimerType(curtime, m_LowSpeedTimers, false); + } + + // High speed timers will + ProcessTimerType(curtime, m_HighSpeedTimers, true); +} + ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags) { ITimer *pTimer; @@ -307,33 +325,34 @@ ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void } pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags); + TimerType& timerType = flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedTimers : m_LowSpeedTimers; if (flags & TIMER_FLAG_REPEAT) { - m_LoopTimers.push_back(pTimer); + timerType.m_LoopTimers.push_back(pTimer); goto return_timer; } - if (m_SingleTimers.size() >= 1) + if (timerType.m_SingleTimers.size() >= 1) { - iter = --m_SingleTimers.end(); + iter = --timerType.m_SingleTimers.end(); if ((*iter)->m_ToExec <= to_exec) { goto normal_insert_end; } } - for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++) + for (iter=timerType.m_SingleTimers.begin(); iter!=timerType.m_SingleTimers.end(); iter++) { if ((*iter)->m_ToExec >= to_exec) { - m_SingleTimers.insert(iter, pTimer); + timerType.m_SingleTimers.insert(iter, pTimer); goto return_timer; } } normal_insert_end: - m_SingleTimers.push_back(pTimer); + timerType.m_SingleTimers.push_back(pTimer); return_timer: return pTimer; @@ -350,11 +369,12 @@ void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) pTimer->m_InExec = true; res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); + TimerType& timerType = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedTimers : m_LowSpeedTimers; if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT)) { pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - m_SingleTimers.remove(pTimer); + timerType.m_SingleTimers.remove(pTimer); m_FreeTimers.push(pTimer); } else @@ -369,7 +389,7 @@ void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) return; } pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - m_LoopTimers.remove(pTimer); + timerType.m_LoopTimers.remove(pTimer); m_FreeTimers.push(pTimer); } } @@ -387,14 +407,15 @@ void TimerSystem::KillTimer(ITimer *pTimer) return; } - pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */ + pTimer->m_InExec = true; /* The timer is not really executed but this check needs to be done */ pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); + TimerType& timerType = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedTimers : m_LowSpeedTimers; if (pTimer->m_Flags & TIMER_FLAG_REPEAT) { - m_LoopTimers.remove(pTimer); + timerType.m_LoopTimers.remove(pTimer); } else { - m_SingleTimers.remove(pTimer); + timerType.m_SingleTimers.remove(pTimer); } m_FreeTimers.push(pTimer); @@ -403,26 +424,21 @@ void TimerSystem::KillTimer(ITimer *pTimer) CStack s_tokill; void TimerSystem::RemoveMapChangeTimers() { - ITimer *pTimer; - TimerIter iter; - - for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++) - { - pTimer = (*iter); - if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE) - { - s_tokill.push(pTimer); - } - } - - for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++) - { - pTimer = (*iter); - if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE) - { - s_tokill.push(pTimer); - } - } + auto KillMapchangeTimers = [](TimerList& timerList) { + for (ITimer* pTimer : timerList) + { + if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE) + { + s_tokill.push(pTimer); + } + } + }; + + KillMapchangeTimers(m_LowSpeedTimers.m_SingleTimers); + KillMapchangeTimers(m_LowSpeedTimers.m_LoopTimers); + + KillMapchangeTimers(m_HighSpeedTimers.m_SingleTimers); + KillMapchangeTimers(m_HighSpeedTimers.m_LoopTimers); while (!s_tokill.empty()) { diff --git a/core/TimerSys.h b/core/TimerSys.h index c5a9b75889..7cdff85244 100644 --- a/core/TimerSys.h +++ b/core/TimerSys.h @@ -41,7 +41,6 @@ using namespace SourceHook; using namespace SourceMod; -typedef List TimerList; typedef List::iterator TimerIter; class SourceMod::ITimer @@ -55,12 +54,23 @@ class SourceMod::ITimer int m_Flags; bool m_InExec; bool m_KillMe; + bool m_HighSpeed; +}; + +class TimerList : public List +{ + }; class TimerSystem : public ITimerSystem, public SMGlobalClass { +public: + struct TimerType { + TimerList m_SingleTimers; + TimerList m_LoopTimers; + }; public: TimerSystem(); ~TimerSystem(); @@ -80,12 +90,14 @@ class TimerSystem : bool GetMapTimeLeft(float *pTime); IMapTimer *GetMapTimer(); public: - void RunFrame(); + void RunFrame(bool timerThink); void RemoveMapChangeTimers(); void GameFrame(bool simulating); private: - List m_SingleTimers; - List m_LoopTimers; + void ProcessTimerType(double curtime, TimerType& timerType, bool isHighSpeed); +private: + TimerType m_LowSpeedTimers; + TimerType m_HighSpeedTimers; CStack m_FreeTimers; IMapTimer *m_pMapTimer; diff --git a/plugins/include/timers.inc b/plugins/include/timers.inc index e74d9beb7e..9acfaf020a 100644 --- a/plugins/include/timers.inc +++ b/plugins/include/timers.inc @@ -39,6 +39,7 @@ #define TIMER_REPEAT (1<<0) /**< Timer will repeat until it returns Plugin_Stop */ #define TIMER_FLAG_NO_MAPCHANGE (1<<1) /**< Timer will not carry over mapchanges */ +#define TIMER_FLAG_TICK_PRECISE (1<<2) /**< Timer will have tick level time precision */ #define TIMER_HNDL_CLOSE (1<<9) /**< Deprecated define, replaced by below */ #define TIMER_DATA_HNDL_CLOSE (1<<9) /**< Timer will automatically call CloseHandle() on its data when finished */ diff --git a/public/ITimerSystem.h b/public/ITimerSystem.h index 5185612736..d8959de76e 100644 --- a/public/ITimerSystem.h +++ b/public/ITimerSystem.h @@ -107,6 +107,7 @@ namespace SourceMod #define TIMER_FLAG_REPEAT (1<<0) /**< Timer will repeat until stopped */ #define TIMER_FLAG_NO_MAPCHANGE (1<<1) /**< Timer will not carry over mapchanges */ + #define TIMER_FLAG_TICK_PRECISE (1<<2) /**< Timer will have tick level time precision */ class ITimerSystem : public SMInterface { From 11b3a1917e28eebc116f12224483d79f1344d095 Mon Sep 17 00:00:00 2001 From: Headline Date: Fri, 19 Sep 2025 00:17:26 -0700 Subject: [PATCH 4/8] Finish my thought --- core/TimerSys.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index f3ff5bf7a5..2677c00189 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -306,7 +306,7 @@ void TimerSystem::RunFrame(bool timerThink) ProcessTimerType(curtime, m_LowSpeedTimers, false); } - // High speed timers will + // High speed timers will always update ProcessTimerType(curtime, m_HighSpeedTimers, true); } From 61025d5ba0b3ed260c72810eec36600913160f2e Mon Sep 17 00:00:00 2001 From: Headline Date: Fri, 19 Sep 2025 00:37:05 -0700 Subject: [PATCH 5/8] Leave one-off timers alone --- core/TimerSys.cpp | 90 +++++++++++++++++++++++++---------------------- core/TimerSys.h | 17 +++------ 2 files changed, 51 insertions(+), 56 deletions(-) diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 2677c00189..466af64b53 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -252,30 +252,13 @@ void TimerSystem::GameFrame(bool simulating) } } -void TimerSystem::ProcessTimerType(double curtime, TimerType& timerType, bool isHighSpeed) +void TimerSystem::ProcessRepeatTimers(double curtime, List& timerList, bool isHighSpeed) { ITimer *pTimer; TimerIter iter; - for (iter=timerType.m_SingleTimers.begin(); iter!=timerType.m_SingleTimers.end(); ) - { - pTimer = (*iter); - if (curtime >= pTimer->m_ToExec) - { - pTimer->m_InExec = true; - pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); - pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - iter = timerType.m_SingleTimers.erase(iter); - m_FreeTimers.push(pTimer); - } - else - { - break; - } - } - - ResultType res; - for (iter=timerType.m_LoopTimers.begin(); iter!=timerType.m_LoopTimers.end(); ) + ResultType res; + for (iter=timerList.begin(); iter!=timerList.end(); ) { pTimer = (*iter); if (curtime >= pTimer->m_ToExec) @@ -285,7 +268,7 @@ void TimerSystem::ProcessTimerType(double curtime, TimerType& timerType, bool is if (pTimer->m_KillMe || (res == Pl_Stop)) { pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - iter = timerType.m_LoopTimers.erase(iter); + iter = timerList.erase(iter); m_FreeTimers.push(pTimer); continue; } @@ -300,14 +283,35 @@ void TimerSystem::RunFrame(bool timerThink) { const double curtime = GetSimulatedTime(); - // Most timers do not need to be updated every frame + //// One-off timers + ITimer *pTimer; + TimerIter iter; + for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); ) + { + pTimer = (*iter); + if (curtime >= pTimer->m_ToExec) + { + pTimer->m_InExec = true; + pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); + pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); + iter = m_SingleTimers.erase(iter); + m_FreeTimers.push(pTimer); + } + else + { + break; + } + } + + //// Repeating timers + // Most repeating timers do not need to be updated every frame if (timerThink) { - ProcessTimerType(curtime, m_LowSpeedTimers, false); + ProcessRepeatTimers(curtime, m_LowSpeedLoopTimers, false); } - // High speed timers will always update - ProcessTimerType(curtime, m_HighSpeedTimers, true); + // High speed repeating timers will always update + ProcessRepeatTimers(curtime, m_HighSpeedLoopTimers, true); } ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags) @@ -325,34 +329,34 @@ ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void } pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags); - TimerType& timerType = flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedTimers : m_LowSpeedTimers; if (flags & TIMER_FLAG_REPEAT) { - timerType.m_LoopTimers.push_back(pTimer); + List timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers; + timerList.push_back(pTimer); goto return_timer; } - if (timerType.m_SingleTimers.size() >= 1) + if (m_SingleTimers.size() >= 1) { - iter = --timerType.m_SingleTimers.end(); + iter = --m_SingleTimers.end(); if ((*iter)->m_ToExec <= to_exec) { goto normal_insert_end; } } - for (iter=timerType.m_SingleTimers.begin(); iter!=timerType.m_SingleTimers.end(); iter++) + for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++) { if ((*iter)->m_ToExec >= to_exec) { - timerType.m_SingleTimers.insert(iter, pTimer); + m_SingleTimers.insert(iter, pTimer); goto return_timer; } } normal_insert_end: - timerType.m_SingleTimers.push_back(pTimer); + m_SingleTimers.push_back(pTimer); return_timer: return pTimer; @@ -369,12 +373,11 @@ void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) pTimer->m_InExec = true; res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); - TimerType& timerType = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedTimers : m_LowSpeedTimers; if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT)) { pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - timerType.m_SingleTimers.remove(pTimer); + m_SingleTimers.remove(pTimer); m_FreeTimers.push(pTimer); } else @@ -388,8 +391,10 @@ void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) pTimer->m_InExec = false; return; } + + List timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers; pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - timerType.m_LoopTimers.remove(pTimer); + timerList.remove(pTimer); m_FreeTimers.push(pTimer); } } @@ -409,13 +414,13 @@ void TimerSystem::KillTimer(ITimer *pTimer) pTimer->m_InExec = true; /* The timer is not really executed but this check needs to be done */ pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); - TimerType& timerType = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedTimers : m_LowSpeedTimers; if (pTimer->m_Flags & TIMER_FLAG_REPEAT) { - timerType.m_LoopTimers.remove(pTimer); + List timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers; + timerList.remove(pTimer); } else { - timerType.m_SingleTimers.remove(pTimer); + m_SingleTimers.remove(pTimer); } m_FreeTimers.push(pTimer); @@ -424,7 +429,7 @@ void TimerSystem::KillTimer(ITimer *pTimer) CStack s_tokill; void TimerSystem::RemoveMapChangeTimers() { - auto KillMapchangeTimers = [](TimerList& timerList) { + const auto KillMapchangeTimers = [](List& timerList) { for (ITimer* pTimer : timerList) { if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE) @@ -434,11 +439,10 @@ void TimerSystem::RemoveMapChangeTimers() } }; - KillMapchangeTimers(m_LowSpeedTimers.m_SingleTimers); - KillMapchangeTimers(m_LowSpeedTimers.m_LoopTimers); + KillMapchangeTimers(m_SingleTimers); - KillMapchangeTimers(m_HighSpeedTimers.m_SingleTimers); - KillMapchangeTimers(m_HighSpeedTimers.m_LoopTimers); + KillMapchangeTimers(m_LowSpeedLoopTimers); + KillMapchangeTimers(m_HighSpeedLoopTimers); while (!s_tokill.empty()) { diff --git a/core/TimerSys.h b/core/TimerSys.h index 7cdff85244..e4a9b7cdc8 100644 --- a/core/TimerSys.h +++ b/core/TimerSys.h @@ -57,20 +57,10 @@ class SourceMod::ITimer bool m_HighSpeed; }; -class TimerList : public List -{ - -}; - class TimerSystem : public ITimerSystem, public SMGlobalClass { -public: - struct TimerType { - TimerList m_SingleTimers; - TimerList m_LoopTimers; - }; public: TimerSystem(); ~TimerSystem(); @@ -94,10 +84,11 @@ class TimerSystem : void RemoveMapChangeTimers(); void GameFrame(bool simulating); private: - void ProcessTimerType(double curtime, TimerType& timerType, bool isHighSpeed); + void ProcessRepeatTimers(double curtime, List& timerList, bool isHighSpeed); private: - TimerType m_LowSpeedTimers; - TimerType m_HighSpeedTimers; + List m_SingleTimers; + List m_LowSpeedLoopTimers; + List m_HighSpeedLoopTimers; CStack m_FreeTimers; IMapTimer *m_pMapTimer; From 6377b00c2c43ac15cb7e7e4e8ca01b9b9203eba8 Mon Sep 17 00:00:00 2001 From: Headline Date: Fri, 19 Sep 2025 00:41:48 -0700 Subject: [PATCH 6/8] Remove unused var --- core/TimerSys.cpp | 1 - core/TimerSys.h | 1 - 2 files changed, 2 deletions(-) diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 466af64b53..a9c7954aea 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -166,7 +166,6 @@ void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, m_Flags = flags; m_InExec = false; m_KillMe = false; - m_HighSpeed = false; } TimerSystem::TimerSystem() diff --git a/core/TimerSys.h b/core/TimerSys.h index e4a9b7cdc8..be482b212a 100644 --- a/core/TimerSys.h +++ b/core/TimerSys.h @@ -54,7 +54,6 @@ class SourceMod::ITimer int m_Flags; bool m_InExec; bool m_KillMe; - bool m_HighSpeed; }; class TimerSystem : From ce45da33f61ed777081799f9ebc01a0a974b5149 Mon Sep 17 00:00:00 2001 From: Headline Date: Fri, 19 Sep 2025 00:44:24 -0700 Subject: [PATCH 7/8] Ensure we're still thinking with TIMER_MIN_ACCURACY --- core/TimerSys.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index a9c7954aea..a89f51a099 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -240,7 +240,7 @@ void TimerSystem::GameFrame(bool simulating) if (timerThink) { - g_fTimerThink = CalcNextThink(g_fTimerThink, gpGlobals->interval_per_tick); + g_fTimerThink = CalcNextThink(g_fTimerThink, TIMER_MIN_ACCURACY); } RunFrameHooks(simulating); From cde98e9d9cfd60b7363f69e85c4ba790ddfa1e19 Mon Sep 17 00:00:00 2001 From: Headline Date: Fri, 19 Sep 2025 13:01:14 -0700 Subject: [PATCH 8/8] Take references to lists --- core/TimerSys.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index a89f51a099..3f0f921384 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -331,7 +331,7 @@ ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void if (flags & TIMER_FLAG_REPEAT) { - List timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers; + List& timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers; timerList.push_back(pTimer); goto return_timer; } @@ -391,7 +391,7 @@ void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) return; } - List timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers; + List& timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers; pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); timerList.remove(pTimer); m_FreeTimers.push(pTimer); @@ -416,7 +416,7 @@ void TimerSystem::KillTimer(ITimer *pTimer) if (pTimer->m_Flags & TIMER_FLAG_REPEAT) { - List timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers; + List& timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers; timerList.remove(pTimer); } else { m_SingleTimers.remove(pTimer);