3 * ================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * ================================================================
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License,
10 * version 3.0, as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to
21 * link the code of this program (as well as its derivative works) to
22 * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any
23 * Game MODs that run on software by the Valve Corporation. You must
24 * obey the GNU General Public License in all respects for all other
25 * code used. Additionally, AlliedModders LLC grants this exception
26 * to all derivative works. AlliedModders LLC defines further
27 * exceptions, found in LICENSE.txt (as of this writing, version
28 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
38 inline float GetSimulatedTime()
40 if (g_SimTicks.ticking)
42 return gpGlobals->curtime;
44 return g_SimTicks.ticktime;
48 void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags)
50 m_Listener = pCallbacks;
51 m_Interval = fInterval;
59 TimerSystem::~TimerSystem()
61 CStack<ITimer *>::iterator iter;
62 for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
66 m_FreeTimers.popall();
69 void TimerSystem::OnSourceModAllInitialized()
71 g_ShareSys.AddInterface(NULL, this);
74 void TimerSystem::OnSourceModLevelChange(const char *mapName)
79 void TimerSystem::RunFrame()
84 float curtime = GetSimulatedTime();
85 for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
88 if (curtime >= pTimer->m_ToExec)
90 pTimer->m_InExec = true;
91 pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
92 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
93 iter = m_SingleTimers.erase(iter);
94 m_FreeTimers.push(pTimer);
101 for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
104 if (curtime >= pTimer->m_ToExec)
106 pTimer->m_InExec = true;
107 res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
108 if (pTimer->m_KillMe || (res == Pl_Stop))
110 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
111 iter = m_LoopTimers.erase(iter);
112 m_FreeTimers.push(pTimer);
115 pTimer->m_InExec = false;
116 pTimer->m_ToExec = curtime + pTimer->m_Interval;
121 m_LastExecTime = curtime;
124 ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
128 float to_exec = GetSimulatedTime() + fInterval;
130 if (m_FreeTimers.empty())
134 pTimer = m_FreeTimers.front();
138 pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags);
140 if (flags & TIMER_FLAG_REPEAT)
142 m_LoopTimers.push_back(pTimer);
146 if (m_SingleTimers.size() >= 1)
148 iter = --m_SingleTimers.end();
149 if ((*iter)->m_ToExec <= to_exec)
155 for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
157 if ((*iter)->m_ToExec >= to_exec)
159 m_SingleTimers.insert(iter, pTimer);
165 m_SingleTimers.push_back(pTimer);
171 void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
175 if (pTimer->m_InExec)
180 pTimer->m_InExec = true;
181 res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
183 if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT))
185 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
186 m_SingleTimers.remove(pTimer);
187 m_FreeTimers.push(pTimer);
189 if ((res != Pl_Stop) && !pTimer->m_KillMe)
193 pTimer->m_ToExec = GetSimulatedTime() + pTimer->m_Interval;
195 pTimer->m_InExec = false;
198 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
199 m_LoopTimers.remove(pTimer);
200 m_FreeTimers.push(pTimer);
204 void TimerSystem::KillTimer(ITimer *pTimer)
208 if (pTimer->m_KillMe)
213 if (pTimer->m_InExec)
215 pTimer->m_KillMe = true;
219 pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */
220 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
222 pList = (pTimer->m_Flags & TIMER_FLAG_REPEAT) ? &m_LoopTimers : &m_SingleTimers;
224 pList->remove(pTimer);
225 m_FreeTimers.push(pTimer);
228 CStack<ITimer *> s_tokill;
229 void TimerSystem::MapChange(bool real_mapchange)
234 for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
237 if (real_mapchange && (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE))
239 s_tokill.push(pTimer);
241 pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
245 for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
248 if (real_mapchange && (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE))
250 s_tokill.push(pTimer);
252 pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
256 while (!s_tokill.empty())
258 KillTimer(s_tokill.front());
262 m_LastExecTime = GetSimulatedTime();