Compare commits

...

10 Commits

Author SHA1 Message Date
sappho
fca288c922
Merge cde98e9d9c into 1819f491b5 2025-11-25 23:21:49 +00:00
dependabot[bot]
1819f491b5
Bump actions/checkout from 5 to 6 (#2378)
Some checks failed
Continuous Integration / ${{ matrix.os_short }}-${{ matrix.compiler_cc }} (clang, clang++, ubuntu-latest, linux) (push) Has been cancelled
Continuous Integration / ${{ matrix.os_short }}-${{ matrix.compiler_cc }} (clang-14, clang++-14, ubuntu-22.04, linux) (push) Has been cancelled
Continuous Integration / ${{ matrix.os_short }}-${{ matrix.compiler_cc }} (msvc, windows-latest, win) (push) Has been cancelled
hl2sdk-mock tests / mock (push) Has been cancelled
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 15:55:07 +00:00
Headline
cde98e9d9c Take references to lists 2025-09-19 13:01:14 -07:00
Headline
ce45da33f6 Ensure we're still thinking with TIMER_MIN_ACCURACY 2025-09-19 00:44:24 -07:00
Headline
6377b00c2c Remove unused var 2025-09-19 00:41:48 -07:00
Headline
61025d5ba0 Leave one-off timers alone 2025-09-19 00:37:05 -07:00
Headline
11b3a1917e Finish my thought 2025-09-19 00:17:26 -07:00
Headline
833d727a71 Let's handle high precision timers separately 2025-09-19 00:15:25 -07:00
stephanie sappho lenzo
107e00c831 undo force push 2025-09-18 23:26:58 -07:00
stephanie sappho lenzo
b52e414ac3 Run timers every tick instead of arbitrarily on 100ms thinks, adding a significantly higher amount of precision 2025-09-18 23:26:58 -07:00
9 changed files with 85 additions and 64 deletions

View File

@ -36,7 +36,7 @@ jobs:
MYSQL_VERSION: '5.7'
MMSOURCE_VERSION: '1.12'
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
submodules: recursive
path: sourcemod

View File

@ -12,20 +12,20 @@ jobs:
mock:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
name: Clone sourcemod
with:
submodules: recursive
path: sourcemod
- uses: actions/checkout@v5
- uses: actions/checkout@v6
name: Clone metamod-source
with:
repository: alliedmodders/metamod-source
submodules: recursive
path: metamod-source
- uses: actions/checkout@v5
- uses: actions/checkout@v6
name: Clone hl2sdk-mock
with:
repository: alliedmodders/hl2sdk-mock

View File

@ -25,7 +25,7 @@ jobs:
env:
ARCH: x86,x86_64
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
submodules: recursive

View File

@ -10,7 +10,7 @@ jobs:
update_translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
submodules: recursive

View File

@ -15,7 +15,7 @@ jobs:
check_translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
name: Setup Python 3.10

View File

@ -36,12 +36,12 @@
#include "ConVarManager.h"
#include "logic_bridge.h"
#define TIMER_MIN_ACCURACY 0.1
#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;
@ -144,9 +144,10 @@ private:
* 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 <= TIMER_MIN_ACCURACY)
const float intervalAccuracy = useTickInterval ? gpGlobals->interval_per_tick : TIMER_MIN_ACCURACY;
if (g_fUniversalTime - last - interval <= intervalAccuracy)
{
return last + interval;
}
@ -234,10 +235,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, TIMER_MIN_ACCURACY);
}
@ -249,12 +251,40 @@ void TimerSystem::GameFrame(bool simulating)
}
}
void TimerSystem::RunFrame()
void TimerSystem::ProcessRepeatTimers(double curtime, List<ITimer*>& timerList, bool isHighSpeed)
{
ITimer *pTimer;
ITimer *pTimer;
TimerIter iter;
double curtime = GetSimulatedTime();
ResultType res;
for (iter=timerList.begin(); iter!=timerList.end(); )
{
pTimer = (*iter);
if (curtime >= pTimer->m_ToExec)
{
pTimer->m_InExec = true;
res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
if (pTimer->m_KillMe || (res == Pl_Stop))
{
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
iter = timerList.erase(iter);
m_FreeTimers.push(pTimer);
continue;
}
pTimer->m_InExec = false;
pTimer->m_ToExec = CalcNextThink(pTimer->m_ToExec, pTimer->m_Interval, isHighSpeed);
}
iter++;
}
}
void TimerSystem::RunFrame(bool timerThink)
{
const double curtime = GetSimulatedTime();
//// One-off timers
ITimer *pTimer;
TimerIter iter;
for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
{
pTimer = (*iter);
@ -272,26 +302,15 @@ void TimerSystem::RunFrame()
}
}
ResultType res;
for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
{
pTimer = (*iter);
if (curtime >= pTimer->m_ToExec)
{
pTimer->m_InExec = true;
res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
if (pTimer->m_KillMe || (res == Pl_Stop))
{
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
iter = m_LoopTimers.erase(iter);
m_FreeTimers.push(pTimer);
continue;
}
pTimer->m_InExec = false;
pTimer->m_ToExec = CalcNextThink(pTimer->m_ToExec, pTimer->m_Interval);
}
iter++;
}
//// Repeating timers
// Most repeating timers do not need to be updated every frame
if (timerThink)
{
ProcessRepeatTimers(curtime, m_LowSpeedLoopTimers, false);
}
// High speed repeating timers will always update
ProcessRepeatTimers(curtime, m_HighSpeedLoopTimers, true);
}
ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
@ -312,7 +331,8 @@ ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void
if (flags & TIMER_FLAG_REPEAT)
{
m_LoopTimers.push_back(pTimer);
List<ITimer*>& timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers;
timerList.push_back(pTimer);
goto return_timer;
}
@ -370,8 +390,10 @@ void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
pTimer->m_InExec = false;
return;
}
List<ITimer*>& timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers;
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
m_LoopTimers.remove(pTimer);
timerList.remove(pTimer);
m_FreeTimers.push(pTimer);
}
}
@ -389,12 +411,13 @@ 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);
if (pTimer->m_Flags & TIMER_FLAG_REPEAT)
{
m_LoopTimers.remove(pTimer);
List<ITimer*>& timerList = pTimer->m_Flags & TIMER_FLAG_TICK_PRECISE ? m_HighSpeedLoopTimers : m_LowSpeedLoopTimers;
timerList.remove(pTimer);
} else {
m_SingleTimers.remove(pTimer);
}
@ -405,26 +428,20 @@ void TimerSystem::KillTimer(ITimer *pTimer)
CStack<ITimer *> s_tokill;
void TimerSystem::RemoveMapChangeTimers()
{
ITimer *pTimer;
TimerIter iter;
const auto KillMapchangeTimers = [](List<ITimer*>& timerList) {
for (ITimer* pTimer : timerList)
{
if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE)
{
s_tokill.push(pTimer);
}
}
};
for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
{
pTimer = (*iter);
if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE)
{
s_tokill.push(pTimer);
}
}
KillMapchangeTimers(m_SingleTimers);
for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
{
pTimer = (*iter);
if (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE)
{
s_tokill.push(pTimer);
}
}
KillMapchangeTimers(m_LowSpeedLoopTimers);
KillMapchangeTimers(m_HighSpeedLoopTimers);
while (!s_tokill.empty())
{

View File

@ -41,7 +41,6 @@
using namespace SourceHook;
using namespace SourceMod;
typedef List<ITimer *> TimerList;
typedef List<ITimer *>::iterator TimerIter;
class SourceMod::ITimer
@ -80,12 +79,15 @@ public: //ITimerSystem
bool GetMapTimeLeft(float *pTime);
IMapTimer *GetMapTimer();
public:
void RunFrame();
void RunFrame(bool timerThink);
void RemoveMapChangeTimers();
void GameFrame(bool simulating);
private:
List<ITimer *> m_SingleTimers;
List<ITimer *> m_LoopTimers;
void ProcessRepeatTimers(double curtime, List<ITimer*>& timerList, bool isHighSpeed);
private:
List<ITimer*> m_SingleTimers;
List<ITimer*> m_LowSpeedLoopTimers;
List<ITimer*> m_HighSpeedLoopTimers;
CStack<ITimer *> m_FreeTimers;
IMapTimer *m_pMapTimer;

View File

@ -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 */

View File

@ -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
{