3 * =============================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
34 #include "sourcemm_api.h"
38 ConVar sm_time_adjustment("sm_time_adjustment", "0", 0, "Adjusts the server time in seconds");
40 time_t GetAdjustedTime(time_t *buf)
42 time_t val = time(NULL) + sm_time_adjustment.GetInt();
50 inline float GetSimulatedTime()
52 return engine->Time();
55 void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags)
57 m_Listener = pCallbacks;
58 m_Interval = fInterval;
66 TimerSystem::TimerSystem()
71 TimerSystem::~TimerSystem()
73 CStack<ITimer *>::iterator iter;
74 for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
78 m_FreeTimers.popall();
81 void TimerSystem::OnSourceModAllInitialized()
83 g_ShareSys.AddInterface(NULL, this);
86 void TimerSystem::OnSourceModLevelChange(const char *mapName)
91 void TimerSystem::RunFrame()
96 float curtime = GetSimulatedTime();
97 for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
100 if (curtime >= pTimer->m_ToExec)
102 pTimer->m_InExec = true;
103 pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
104 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
105 iter = m_SingleTimers.erase(iter);
106 m_FreeTimers.push(pTimer);
112 if (m_fnTimeLeft != NULL && m_MapEndTimers.size())
114 float time_left = m_fnTimeLeft();
115 for (iter=m_MapEndTimers.begin(); iter!=m_MapEndTimers.end();)
118 if ((*iter)->m_Interval < time_left)
120 pTimer->m_InExec = true;
121 pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
122 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
123 iter = m_MapEndTimers.erase(iter);
124 m_FreeTimers.push(pTimer);
132 for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
135 if (curtime >= pTimer->m_ToExec)
137 pTimer->m_InExec = true;
138 res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
139 if (pTimer->m_KillMe || (res == Pl_Stop))
141 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
142 iter = m_LoopTimers.erase(iter);
143 m_FreeTimers.push(pTimer);
146 pTimer->m_InExec = false;
147 pTimer->m_ToExec = curtime + pTimer->m_Interval;
152 m_LastExecTime = curtime;
155 ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
159 float to_exec = GetSimulatedTime() + fInterval;
161 if ((flags & TIMER_FLAG_BEFORE_MAP_END)
162 && m_fnTimeLeft == NULL)
167 if (m_FreeTimers.empty())
171 pTimer = m_FreeTimers.front();
175 pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags);
177 if (flags & TIMER_FLAG_REPEAT)
179 m_LoopTimers.push_back(pTimer);
183 if (flags & TIMER_FLAG_BEFORE_MAP_END)
185 for (iter=m_MapEndTimers.begin(); iter!=m_MapEndTimers.end(); iter++)
187 if (fInterval >= (*iter)->m_Interval)
189 m_MapEndTimers.insert(iter, pTimer);
194 m_MapEndTimers.push_back(pTimer);
196 if (m_SingleTimers.size() >= 1)
198 iter = --m_SingleTimers.end();
199 if ((*iter)->m_ToExec <= to_exec)
201 goto normal_insert_end;
205 for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
207 if ((*iter)->m_ToExec >= to_exec)
209 m_SingleTimers.insert(iter, pTimer);
215 m_SingleTimers.push_back(pTimer);
222 void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
226 if (pTimer->m_InExec)
231 pTimer->m_InExec = true;
232 res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
234 if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT))
236 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
237 if (pTimer->m_Flags & TIMER_FLAG_BEFORE_MAP_END)
239 m_MapEndTimers.remove(pTimer);
241 m_SingleTimers.remove(pTimer);
243 m_FreeTimers.push(pTimer);
245 if ((res != Pl_Stop) && !pTimer->m_KillMe)
249 pTimer->m_ToExec = GetSimulatedTime() + pTimer->m_Interval;
251 pTimer->m_InExec = false;
254 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
255 m_LoopTimers.remove(pTimer);
256 m_FreeTimers.push(pTimer);
260 void TimerSystem::KillTimer(ITimer *pTimer)
262 if (pTimer->m_KillMe)
267 if (pTimer->m_InExec)
269 pTimer->m_KillMe = true;
273 pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */
274 pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
276 if (pTimer->m_Flags & TIMER_FLAG_REPEAT)
278 m_LoopTimers.remove(pTimer);
279 } else if (pTimer->m_Flags & TIMER_FLAG_BEFORE_MAP_END) {
280 m_MapEndTimers.remove(pTimer);
282 m_SingleTimers.remove(pTimer);
285 m_FreeTimers.push(pTimer);
288 CStack<ITimer *> s_tokill;
289 void TimerSystem::MapChange(bool real_mapchange)
294 for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
297 if (real_mapchange && (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE))
299 s_tokill.push(pTimer);
301 pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
305 for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
308 if (real_mapchange && (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE))
310 s_tokill.push(pTimer);
312 pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
318 for (iter=m_MapEndTimers.begin(); iter!=m_MapEndTimers.end(); iter++)
321 s_tokill.push(pTimer);
325 while (!s_tokill.empty())
327 KillTimer(s_tokill.front());
331 m_LastExecTime = GetSimulatedTime();
334 SM_TIMELEFT_FUNCTION TimerSystem::SetTimeLeftFunction(SM_TIMELEFT_FUNCTION fn)
336 SM_TIMELEFT_FUNCTION old = m_fnTimeLeft;