core/TimerSys.cpp
author Michael McKoy <ferret99gt@gmail.com>
Wed Aug 08 23:26:42 2007 +0000 (2007-08-08)
changeset 1280 13c62962a9ef
parent 1231 17badaf66ce4
child 1330 ab94316bb52b
permissions -rw-r--r--
Corrected filename in header of basefuncommands.sp
     1 /**
     2  * vim: set ts=4 :
     3  * ================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * ================================================================
     7  *
     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.
    11  * 
    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.
    16  *
    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/>.
    19  *
    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>.
    29  *
    30  * Version: $Id$
    31  */
    32 
    33 #include "TimerSys.h"
    34 
    35 TimerSystem g_Timers;
    36 TickInfo g_SimTicks;
    37 
    38 inline float GetSimulatedTime()
    39 {
    40 	if (g_SimTicks.ticking)
    41 	{
    42 		return gpGlobals->curtime;
    43 	} else {
    44 		return g_SimTicks.ticktime;
    45 	}
    46 }
    47 
    48 void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags)
    49 {
    50 	m_Listener = pCallbacks;
    51 	m_Interval = fInterval;
    52 	m_ToExec = fToExec;
    53 	m_pData = pData;
    54 	m_Flags = flags;
    55 	m_InExec = false;
    56 	m_KillMe = false;
    57 }
    58 
    59 TimerSystem::~TimerSystem()
    60 {
    61 	CStack<ITimer *>::iterator iter;
    62 	for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
    63 	{
    64 		delete (*iter);
    65 	}
    66 	m_FreeTimers.popall();
    67 }
    68 
    69 void TimerSystem::OnSourceModAllInitialized()
    70 {
    71 	g_ShareSys.AddInterface(NULL, this);
    72 }
    73 
    74 void TimerSystem::OnSourceModLevelChange(const char *mapName)
    75 {
    76 	MapChange(true);
    77 }
    78 
    79 void TimerSystem::RunFrame()
    80 {
    81 	ITimer *pTimer;
    82 	TimerIter iter;
    83 
    84 	float curtime = GetSimulatedTime();
    85 	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
    86 	{
    87 		pTimer = (*iter);
    88 		if (curtime >= pTimer->m_ToExec)
    89 		{
    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);
    95 		} else {
    96 			break;
    97 		}
    98 	}
    99 
   100 	ResultType res;
   101 	for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
   102 	{
   103 		pTimer = (*iter);
   104 		if (curtime >= pTimer->m_ToExec)
   105 		{
   106 			pTimer->m_InExec = true;
   107 			res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
   108 			if (pTimer->m_KillMe || (res == Pl_Stop))
   109 			{
   110 				pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   111 				iter = m_LoopTimers.erase(iter);
   112 				m_FreeTimers.push(pTimer);
   113 				continue;
   114 			}
   115 			pTimer->m_InExec = false;
   116 			pTimer->m_ToExec = curtime + pTimer->m_Interval;
   117 		}
   118 		iter++;
   119 	}
   120 
   121 	m_LastExecTime = curtime;
   122 }
   123 
   124 ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
   125 {
   126 	ITimer *pTimer;
   127 	TimerIter iter;
   128 	float to_exec = GetSimulatedTime() + fInterval;
   129 
   130 	if (m_FreeTimers.empty())
   131 	{
   132 		pTimer = new ITimer;
   133 	} else {
   134 		pTimer = m_FreeTimers.front();
   135 		m_FreeTimers.pop();
   136 	}
   137 
   138 	pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags);
   139 
   140 	if (flags & TIMER_FLAG_REPEAT)
   141 	{
   142 		m_LoopTimers.push_back(pTimer);
   143 		goto return_timer;
   144 	}
   145 
   146 	if (m_SingleTimers.size() >= 1)
   147 	{
   148 		iter = --m_SingleTimers.end();
   149 		if ((*iter)->m_ToExec <= to_exec)
   150 		{
   151 			goto insert_end;
   152 		}
   153 	}
   154 
   155 	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
   156 	{
   157 		if ((*iter)->m_ToExec >= to_exec)
   158 		{
   159 			m_SingleTimers.insert(iter, pTimer);
   160 			goto return_timer;
   161 		}
   162 	}
   163 
   164 insert_end:
   165 	m_SingleTimers.push_back(pTimer);
   166 
   167 return_timer:
   168 	return pTimer;
   169 }
   170 
   171 void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
   172 {
   173 	ResultType res;
   174 
   175 	if (pTimer->m_InExec)
   176 	{
   177 		return;
   178 	}
   179 
   180 	pTimer->m_InExec = true;
   181 	res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
   182 
   183 	if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT))
   184 	{
   185 		pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   186 		m_SingleTimers.remove(pTimer);
   187 		m_FreeTimers.push(pTimer);
   188 	} else {
   189 		if ((res != Pl_Stop) && !pTimer->m_KillMe)
   190 		{
   191 			if (delayExec)
   192 			{
   193 				pTimer->m_ToExec = GetSimulatedTime() + pTimer->m_Interval;
   194 			}
   195 			pTimer->m_InExec = false;
   196 			return;
   197 		}
   198 		pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   199 		m_LoopTimers.remove(pTimer);
   200 		m_FreeTimers.push(pTimer);
   201 	}
   202 }
   203 
   204 void TimerSystem::KillTimer(ITimer *pTimer)
   205 {
   206 	TimerList *pList;
   207 
   208 	if (pTimer->m_KillMe)
   209 	{
   210 		return;
   211 	}
   212 
   213 	if (pTimer->m_InExec)
   214 	{
   215 		pTimer->m_KillMe = true;
   216 		return;
   217 	}
   218 
   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);
   221 
   222 	pList = (pTimer->m_Flags & TIMER_FLAG_REPEAT) ? &m_LoopTimers : &m_SingleTimers;
   223 
   224 	pList->remove(pTimer);
   225 	m_FreeTimers.push(pTimer);
   226 }
   227 
   228 CStack<ITimer *> s_tokill;
   229 void TimerSystem::MapChange(bool real_mapchange)
   230 {
   231 	ITimer *pTimer;
   232 	TimerIter iter;
   233 
   234 	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
   235 	{
   236 		pTimer = (*iter);
   237 		if (real_mapchange && (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE))
   238 		{
   239 			s_tokill.push(pTimer);
   240 		} else {
   241 			pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
   242 		}
   243 	}
   244 
   245 	for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
   246 	{
   247 		pTimer = (*iter);
   248 		if (real_mapchange && (pTimer->m_Flags & TIMER_FLAG_NO_MAPCHANGE))
   249 		{
   250 			s_tokill.push(pTimer);
   251 		} else {
   252 			pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
   253 		}
   254 	}
   255 
   256 	while (!s_tokill.empty())
   257 	{
   258 		KillTimer(s_tokill.front());
   259 		s_tokill.pop();
   260 	}
   261 
   262 	m_LastExecTime = GetSimulatedTime();
   263 }