core/TimerSys.cpp
author David Anderson <dvander@alliedmods.net>
Wed May 02 22:35:51 2007 +0000 (2007-05-02)
changeset 727 fade10824d88
parent 673 fc1d50579d06
child 1108 fafe809b16ca
permissions -rw-r--r--
attempted fix for amb243, timers now simulate ticks if gameframe doesn't give changed curtimes
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "TimerSys.h"
    16 
    17 TimerSystem g_Timers;
    18 TickInfo g_SimTicks;
    19 
    20 inline float GetSimulatedTime()
    21 {
    22 	if (g_SimTicks.ticking)
    23 	{
    24 		return gpGlobals->curtime;
    25 	} else {
    26 		return g_SimTicks.ticktime;
    27 	}
    28 }
    29 
    30 void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags)
    31 {
    32 	m_Listener = pCallbacks;
    33 	m_Interval = fInterval;
    34 	m_ToExec = fToExec;
    35 	m_pData = pData;
    36 	m_Flags = flags;
    37 	m_InExec = false;
    38 	m_KillMe = false;
    39 }
    40 
    41 TimerSystem::~TimerSystem()
    42 {
    43 	CStack<ITimer *>::iterator iter;
    44 	for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
    45 	{
    46 		delete (*iter);
    47 	}
    48 	m_FreeTimers.popall();
    49 }
    50 
    51 void TimerSystem::OnSourceModAllInitialized()
    52 {
    53 	g_ShareSys.AddInterface(NULL, this);
    54 }
    55 
    56 void TimerSystem::OnSourceModLevelChange(const char *mapName)
    57 {
    58 	MapChange();
    59 }
    60 
    61 void TimerSystem::RunFrame()
    62 {
    63 	ITimer *pTimer;
    64 	TimerIter iter;
    65 
    66 	float curtime = GetSimulatedTime();
    67 	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
    68 	{
    69 		pTimer = (*iter);
    70 		if (curtime >= pTimer->m_ToExec)
    71 		{
    72 			pTimer->m_InExec = true;
    73 			pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
    74 			pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
    75 			iter = m_SingleTimers.erase(iter);
    76 			m_FreeTimers.push(pTimer);
    77 		} else {
    78 			break;
    79 		}
    80 	}
    81 
    82 	ResultType res;
    83 	for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
    84 	{
    85 		pTimer = (*iter);
    86 		if (curtime >= pTimer->m_ToExec)
    87 		{
    88 			pTimer->m_InExec = true;
    89 			res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
    90 			if (pTimer->m_KillMe || (res == Pl_Stop))
    91 			{
    92 				pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
    93 				iter = m_LoopTimers.erase(iter);
    94 				m_FreeTimers.push(pTimer);
    95 				continue;
    96 			}
    97 			pTimer->m_InExec = false;
    98 			pTimer->m_ToExec = curtime + pTimer->m_Interval;
    99 		}
   100 		iter++;
   101 	}
   102 
   103 	m_LastExecTime = curtime;
   104 }
   105 
   106 ITimer *TimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
   107 {
   108 	ITimer *pTimer;
   109 	TimerIter iter;
   110 	float to_exec = GetSimulatedTime() + fInterval;
   111 
   112 	if (m_FreeTimers.empty())
   113 	{
   114 		pTimer = new ITimer;
   115 	} else {
   116 		pTimer = m_FreeTimers.front();
   117 		m_FreeTimers.pop();
   118 	}
   119 
   120 	pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags);
   121 
   122 	if (flags & TIMER_FLAG_REPEAT)
   123 	{
   124 		m_LoopTimers.push_back(pTimer);
   125 		goto return_timer;
   126 	}
   127 
   128 	if (m_SingleTimers.size() >= 1)
   129 	{
   130 		iter = --m_SingleTimers.end();
   131 		if ((*iter)->m_ToExec <= to_exec)
   132 		{
   133 			goto insert_end;
   134 		}
   135 	}
   136 
   137 	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
   138 	{
   139 		if ((*iter)->m_ToExec >= to_exec)
   140 		{
   141 			m_SingleTimers.insert(iter, pTimer);
   142 			goto return_timer;
   143 		}
   144 	}
   145 
   146 insert_end:
   147 	m_SingleTimers.push_back(pTimer);
   148 
   149 return_timer:
   150 	return pTimer;
   151 }
   152 
   153 void TimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
   154 {
   155 	ResultType res;
   156 
   157 	if (pTimer->m_InExec)
   158 	{
   159 		return;
   160 	}
   161 
   162 	pTimer->m_InExec = true;
   163 	res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
   164 
   165 	if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT))
   166 	{
   167 		pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   168 		m_SingleTimers.remove(pTimer);
   169 		m_FreeTimers.push(pTimer);
   170 	} else {
   171 		if ((res != Pl_Stop) && !pTimer->m_KillMe)
   172 		{
   173 			if (delayExec)
   174 			{
   175 				pTimer->m_ToExec = GetSimulatedTime() + pTimer->m_Interval;
   176 			}
   177 			pTimer->m_InExec = false;
   178 			return;
   179 		}
   180 		pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   181 		m_LoopTimers.remove(pTimer);
   182 		m_FreeTimers.push(pTimer);
   183 	}
   184 }
   185 
   186 void TimerSystem::KillTimer(ITimer *pTimer)
   187 {
   188 	TimerList *pList;
   189 
   190 	if (pTimer->m_KillMe)
   191 	{
   192 		return;
   193 	}
   194 
   195 	if (pTimer->m_InExec)
   196 	{
   197 		pTimer->m_KillMe = true;
   198 		return;
   199 	}
   200 
   201 	pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */
   202 	pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   203 
   204 	pList = (pTimer->m_Flags & TIMER_FLAG_REPEAT) ? &m_LoopTimers : &m_SingleTimers;
   205 
   206 	pList->remove(pTimer);
   207 	m_FreeTimers.push(pTimer);
   208 }
   209 
   210 void TimerSystem::MapChange()
   211 {
   212 	ITimer *pTimer;
   213 	TimerIter iter;
   214 
   215 	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
   216 	{
   217 		pTimer = (*iter);
   218 		pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
   219 	}
   220 
   221 	for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
   222 	{
   223 		pTimer = (*iter);
   224 		pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + GetSimulatedTime();
   225 	}
   226 
   227 	m_LastExecTime = GetSimulatedTime();
   228 }