2007-03-10 14:16:19 +01:00
|
|
|
/**
|
2007-03-22 22:50:20 +01:00
|
|
|
* vim: set ts=4 :
|
2007-08-15 08:19:30 +02:00
|
|
|
* =============================================================================
|
2007-08-01 04:12:47 +02:00
|
|
|
* SourceMod
|
|
|
|
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
2007-08-15 08:19:30 +02:00
|
|
|
* =============================================================================
|
2007-03-22 22:50:20 +01:00
|
|
|
*
|
2007-08-15 08:19:30 +02:00
|
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
|
|
* Free Software Foundation.
|
2007-08-01 04:12:47 +02:00
|
|
|
*
|
2007-08-15 08:19:30 +02:00
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
* details.
|
2007-08-01 04:12:47 +02:00
|
|
|
*
|
2007-08-15 08:19:30 +02:00
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
2007-08-01 04:12:47 +02:00
|
|
|
*
|
2007-08-15 08:19:30 +02:00
|
|
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
|
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
|
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
|
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
|
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
|
|
* this exception to all derivative works. AlliedModders LLC defines further
|
|
|
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
|
|
* or <http://www.sourcemod.net/license.php>.
|
2007-03-22 22:50:20 +01:00
|
|
|
*
|
|
|
|
* Version: $Id$
|
|
|
|
*/
|
2007-03-10 14:16:19 +01:00
|
|
|
|
2007-08-26 20:41:57 +02:00
|
|
|
#include <time.h>
|
2007-03-10 22:26:04 +01:00
|
|
|
#include "TimerSys.h"
|
2007-08-26 20:41:57 +02:00
|
|
|
#include "sourcemm_api.h"
|
2007-03-10 14:16:19 +01:00
|
|
|
|
2007-03-15 05:45:17 +01:00
|
|
|
TimerSystem g_Timers;
|
2007-05-03 00:35:51 +02:00
|
|
|
TickInfo g_SimTicks;
|
|
|
|
|
2007-08-26 20:41:57 +02:00
|
|
|
ConVar sm_time_adjustment("sm_time_adjustment", "0", 0, "Adjusts the server time in seconds");
|
|
|
|
|
|
|
|
time_t GetAdjustedTime(time_t *buf)
|
|
|
|
{
|
|
|
|
time_t val = time(NULL) + sm_time_adjustment.GetInt();
|
|
|
|
if (buf)
|
|
|
|
{
|
|
|
|
*buf = val;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2007-05-03 00:35:51 +02:00
|
|
|
inline float GetSimulatedTime()
|
|
|
|
{
|
|
|
|
if (g_SimTicks.ticking)
|
|
|
|
{
|
|
|
|
return gpGlobals->curtime;
|
|
|
|
} else {
|
|
|
|
return g_SimTicks.ticktime;
|
|
|
|
}
|
|
|
|
}
|
2007-03-10 14:16:19 +01:00
|
|
|
|
|
|
|
void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags)
|
|
|
|
{
|
|
|
|
m_Listener = pCallbacks;
|
|
|
|
m_Interval = fInterval;
|
|
|
|
m_ToExec = fToExec;
|
|
|
|
m_pData = pData;
|
|
|
|
m_Flags = flags;
|
|
|
|
m_InExec = false;
|
|
|
|
m_KillMe = false;
|
|
|
|
}
|
|
|
|
|
2007-03-17 01:55:46 +01:00
|
|
|
TimerSystem::~TimerSystem()
|
|
|
|
{
|
|
|
|
CStack<ITimer *>::iterator iter;
|
|
|
|
for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
|
|
|
|
{
|
|
|
|
delete (*iter);
|
|
|
|
}
|
|
|
|
m_FreeTimers.popall();
|
|
|
|
}
|
|
|
|
|
2007-03-15 05:45:17 +01:00
|
|
|
void TimerSystem::OnSourceModAllInitialized()
|
2007-03-10 14:16:19 +01:00
|
|
|
{
|
|
|
|
g_ShareSys.AddInterface(NULL, this);
|
|
|
|
}
|
|
|
|
|
2007-04-07 05:58:20 +02:00
|
|
|
void TimerSystem::OnSourceModLevelChange(const char *mapName)
|
|
|
|
{
|
2007-07-22 18:01:01 +02:00
|
|
|
MapChange(true);
|
2007-04-07 05:58:20 +02:00
|
|
|
}
|
|
|
|
|
2007-03-15 05:45:17 +01:00
|
|
|
void TimerSystem::RunFrame()
|
2007-03-10 14:16:19 +01:00
|
|
|
{
|
|
|
|
ITimer *pTimer;
|
|
|
|
TimerIter iter;
|
|
|
|
|
2007-05-03 00:35:51 +02:00
|
|
|
float curtime = GetSimulatedTime();
|
2007-03-10 14:16:19 +01:00
|
|
|
for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
|
|
|
|
{
|
|
|
|
pTimer = (*iter);
|
2007-05-03 00:35:51 +02:00
|
|
|
if (curtime >= pTimer->m_ToExec)
|
2007-03-10 14:16:19 +01:00
|
|
|
{
|
|
|
|
pTimer->m_InExec = true;
|
|
|
|
pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
|
2007-03-14 12:34:03 +01:00
|
|
|
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
|
2007-03-10 14:16:19 +01:00
|
|
|
iter = m_SingleTimers.erase(iter);
|
|
|
|
m_FreeTimers.push(pTimer);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ResultType res;
|
|
|
|
for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
|
|
|
|
{
|
|
|
|
pTimer = (*iter);
|
2007-05-03 00:35:51 +02:00
|
|
|
if (curtime >= pTimer->m_ToExec)
|
2007-03-10 14:16:19 +01:00
|
|
|
{
|
|
|
|
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;
|
2007-05-03 00:35:51 +02:00
|
|
|
pTimer->m_ToExec = curtime + pTimer->m_Interval;
|
2007-03-10 14:16:19 +01:00
|
|
|
}
|
|
|
|
iter++;
|
|
|
|
}
|
|
|
|
|
2007-05-03 00:35:51 +02:00
|
|
|
m_LastExecTime = curtime;
|
2007-03-10 14:16:19 +01:00
|
|
|
}
|
|
|
|
|
2007-03-15 05:45:17 +01:00
|
|
|
ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
|
2007-03-10 14:16:19 +01:00
|
|
|
{
|
|
|
|
ITimer *pTimer;
|
|
|
|
TimerIter iter;
|
2007-05-03 00:35:51 +02:00
|
|
|
float to_exec = GetSimulatedTime() + fInterval;
|
2007-03-10 14:16:19 +01:00
|
|
|
|
|
|
|
if (m_FreeTimers.empty())
|
|
|
|
{
|
|
|
|
pTimer = new ITimer;
|
|
|
|
} else {
|
|
|
|
pTimer = m_FreeTimers.front();
|
|
|
|
m_FreeTimers.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags);
|
|
|
|
|
|
|
|
if (flags & TIMER_FLAG_REPEAT)
|
|
|
|
{
|
|
|
|
m_LoopTimers.push_back(pTimer);
|
|
|
|
goto return_timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_SingleTimers.size() >= 1)
|
|
|
|
{
|
|
|
|
iter = --m_SingleTimers.end();
|
|
|
|
if ((*iter)->m_ToExec <= to_exec)
|
|
|
|
{
|
|
|
|
goto insert_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
|
|
|
|
{
|
|
|
|
if ((*iter)->m_ToExec >= to_exec)
|
|
|
|
{
|
|
|
|
m_SingleTimers.insert(iter, pTimer);
|
|
|
|
goto return_timer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
insert_end:
|
|
|
|
m_SingleTimers.push_back(pTimer);
|
|
|
|
|
|
|
|
return_timer:
|
|
|
|
return pTimer;
|
|
|
|
}
|
|
|
|
|
2007-03-15 05:45:17 +01:00
|
|
|
void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
|
2007-03-10 14:16:19 +01:00
|
|
|
{
|
|
|
|
ResultType res;
|
|
|
|
|
|
|
|
if (pTimer->m_InExec)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pTimer->m_InExec = true;
|
|
|
|
res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
|
|
|
|
|
|
|
|
if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT))
|
|
|
|
{
|
|
|
|
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
|
|
|
|
m_SingleTimers.remove(pTimer);
|
|
|
|
m_FreeTimers.push(pTimer);
|
|
|
|
} else {
|
2007-03-14 12:34:03 +01:00
|
|
|
if ((res != Pl_Stop) && !pTimer->m_KillMe)
|
2007-03-10 14:16:19 +01:00
|
|
|
{
|
2007-03-14 12:34:03 +01:00
|
|
|
if (delayExec)
|
|
|
|
{
|
2007-05-03 00:35:51 +02:00
|
|
|
pTimer->m_ToExec = GetSimulatedTime() + pTimer->m_Interval;
|
2007-03-14 12:34:03 +01:00
|
|
|
}
|
2007-03-10 14:16:19 +01:00
|
|
|
pTimer->m_InExec = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
|
|
|
|
m_LoopTimers.remove(pTimer);
|
|
|
|
m_FreeTimers.push(pTimer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-15 05:45:17 +01:00
|
|
|
void TimerSystem::KillTimer(ITimer *pTimer)
|
2007-03-10 14:16:19 +01:00
|
|
|
{
|
|
|
|
TimerList *pList;
|
|
|
|
|
|
|
|
if (pTimer->m_KillMe)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pTimer->m_InExec)
|
|
|
|
{
|
|
|
|
pTimer->m_KillMe = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */
|
|
|
|
pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
|
|
|
|
|
|
|
|
pList = (pTimer->m_Flags & TIMER_FLAG_REPEAT) ? &m_LoopTimers : &m_SingleTimers;
|
|
|
|
|
|
|
|
pList->remove(pTimer);
|
|
|
|
m_FreeTimers.push(pTimer);
|
|
|
|
}
|
|
|
|
|
2007-07-14 03:55:15 +02:00
|
|
|
CStack<ITimer *> s_tokill;
|
2007-07-22 18:01:01 +02:00
|
|
|
void TimerSystem::MapChange(bool real_mapchange)
|
2007-03-10 14:16:19 +01:00
|
|
|
{
|
|
|
|
ITimer *pTimer;
|
|
|
|
TimerIter iter;
|
|
|
|
|
|
|
|
for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
|
|
|
|
{
|
|
|
|
pTimer = (*iter);
|
2007-07-22 18:01:01 +02:00
|
|
|
if (real_mapchange && (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE))
|
2007-07-14 03:55:15 +02:00
|
|
|
{
|
|
|
|
s_tokill.push(pTimer);
|
|
|
|
} else {
|
|
|
|
pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
|
|
|
|
}
|
2007-03-10 14:16:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
|
|
|
|
{
|
|
|
|
pTimer = (*iter);
|
2007-07-22 18:01:01 +02:00
|
|
|
if (real_mapchange && (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE))
|
2007-07-14 03:55:15 +02:00
|
|
|
{
|
|
|
|
s_tokill.push(pTimer);
|
|
|
|
} else {
|
|
|
|
pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!s_tokill.empty())
|
|
|
|
{
|
|
|
|
KillTimer(s_tokill.front());
|
|
|
|
s_tokill.pop();
|
2007-03-10 14:16:19 +01:00
|
|
|
}
|
2007-05-03 00:35:51 +02:00
|
|
|
|
|
|
|
m_LastExecTime = GetSimulatedTime();
|
2007-03-10 14:16:19 +01:00
|
|
|
}
|