core/TimerSys.cpp
author David Anderson <dvander@alliedmods.net>
Mon Mar 12 00:06:20 2007 +0000 (2007-03-12)
changeset 599 3a098eff4890
parent 592 c2a2c38f1331
child 612 e000559527a3
permissions -rw-r--r--
used a better error number
     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 CTimerSystem g_Timers;
    18 
    19 void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags)
    20 {
    21 	m_Listener = pCallbacks;
    22 	m_Interval = fInterval;
    23 	m_ToExec = fToExec;
    24 	m_pData = pData;
    25 	m_Flags = flags;
    26 	m_InExec = false;
    27 	m_KillMe = false;
    28 }
    29 
    30 void CTimerSystem::OnSourceModAllInitialized()
    31 {
    32 	g_ShareSys.AddInterface(NULL, this);
    33 }
    34 
    35 void CTimerSystem::RunFrame()
    36 {
    37 	ITimer *pTimer;
    38 	TimerIter iter;
    39 
    40 	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
    41 	{
    42 		pTimer = (*iter);
    43 		if (gpGlobals->curtime >= pTimer->m_ToExec)
    44 		{
    45 			pTimer->m_InExec = true;
    46 			pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
    47 			if (pTimer->m_KillMe)
    48 			{
    49 				pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
    50 			}
    51 			iter = m_SingleTimers.erase(iter);
    52 			m_FreeTimers.push(pTimer);
    53 		} else {
    54 			break;
    55 		}
    56 	}
    57 
    58 	ResultType res;
    59 	for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
    60 	{
    61 		pTimer = (*iter);
    62 		if (gpGlobals->curtime >= pTimer->m_ToExec)
    63 		{
    64 			pTimer->m_InExec = true;
    65 			res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
    66 			if (pTimer->m_KillMe || (res == Pl_Stop))
    67 			{
    68 				pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
    69 				iter = m_LoopTimers.erase(iter);
    70 				m_FreeTimers.push(pTimer);
    71 				continue;
    72 			}
    73 			pTimer->m_InExec = false;
    74 			pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval;
    75 		}
    76 		iter++;
    77 	}
    78 
    79 	m_LastExecTime = gpGlobals->curtime;
    80 }
    81 
    82 ITimer *CTimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
    83 {
    84 	ITimer *pTimer;
    85 	TimerIter iter;
    86 	float to_exec = gpGlobals->curtime + fInterval;
    87 
    88 	if (m_FreeTimers.empty())
    89 	{
    90 		pTimer = new ITimer;
    91 	} else {
    92 		pTimer = m_FreeTimers.front();
    93 		m_FreeTimers.pop();
    94 	}
    95 
    96 	pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags);
    97 
    98 	if (flags & TIMER_FLAG_REPEAT)
    99 	{
   100 		m_LoopTimers.push_back(pTimer);
   101 		goto return_timer;
   102 	}
   103 
   104 	if (m_SingleTimers.size() >= 1)
   105 	{
   106 		iter = --m_SingleTimers.end();
   107 		if ((*iter)->m_ToExec <= to_exec)
   108 		{
   109 			goto insert_end;
   110 		}
   111 	}
   112 
   113 	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
   114 	{
   115 		if ((*iter)->m_ToExec >= to_exec)
   116 		{
   117 			m_SingleTimers.insert(iter, pTimer);
   118 			goto return_timer;
   119 		}
   120 	}
   121 
   122 insert_end:
   123 	m_SingleTimers.push_back(pTimer);
   124 
   125 return_timer:
   126 	return pTimer;
   127 }
   128 
   129 void CTimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
   130 {
   131 	ResultType res;
   132 
   133 	if (pTimer->m_InExec)
   134 	{
   135 		return;
   136 	}
   137 
   138 	pTimer->m_InExec = true;
   139 	res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
   140 
   141 	if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT))
   142 	{
   143 		pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   144 		m_SingleTimers.remove(pTimer);
   145 		m_FreeTimers.push(pTimer);
   146 	} else {
   147 		if (delayExec && (res != Pl_Stop) && !pTimer->m_KillMe)
   148 		{
   149 			pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval;
   150 			pTimer->m_InExec = false;
   151 			return;
   152 		}
   153 		pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   154 		m_LoopTimers.remove(pTimer);
   155 		m_FreeTimers.push(pTimer);
   156 	}
   157 }
   158 
   159 void CTimerSystem::KillTimer(ITimer *pTimer)
   160 {
   161 	TimerList *pList;
   162 
   163 	if (pTimer->m_KillMe)
   164 	{
   165 		return;
   166 	}
   167 
   168 	if (pTimer->m_InExec)
   169 	{
   170 		pTimer->m_KillMe = true;
   171 		return;
   172 	}
   173 
   174 	pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */
   175 	pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   176 
   177 	pList = (pTimer->m_Flags & TIMER_FLAG_REPEAT) ? &m_LoopTimers : &m_SingleTimers;
   178 
   179 	pList->remove(pTimer);
   180 	m_FreeTimers.push(pTimer);
   181 }
   182 
   183 void CTimerSystem::MapChange()
   184 {
   185 	ITimer *pTimer;
   186 	TimerIter iter;
   187 
   188 	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
   189 	{
   190 		pTimer = (*iter);
   191 		pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + gpGlobals->curtime;
   192 	}
   193 
   194 	for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
   195 	{
   196 		pTimer = (*iter);
   197 		pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + gpGlobals->curtime;
   198 	}
   199 }