Added timer system implementation
authorBorja Ferrer <faluco@alliedmods.net>
Sat Mar 10 13:16:19 2007 +0000 (2007-03-10)
changeset 587e9f3bbe8ba5d
parent 586 1e73cb333b19
child 588 d8ee541ca75e
Added timer system implementation
core/CTimerSys.cpp
core/CTimerSys.h
core/msvc8/sourcemod_mm.vcproj
core/sourcemod.cpp
public/ITimerSystem.h
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/core/CTimerSys.cpp	Sat Mar 10 13:16:19 2007 +0000
     1.3 @@ -0,0 +1,199 @@
     1.4 +/**
     1.5 +* vim: set ts=4 :
     1.6 +* ===============================================================
     1.7 +* SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     1.8 +* ===============================================================
     1.9 +*
    1.10 +* This file is not open source and may not be copied without explicit
    1.11 +* written permission of AlliedModders LLC.  This file may not be redistributed 
    1.12 +* in whole or significant part.
    1.13 +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    1.14 +*
    1.15 +* Version: $Id$
    1.16 +*/
    1.17 +
    1.18 +#include "CTimerSys.h"
    1.19 +
    1.20 +CTimerSystem g_Timers;
    1.21 +
    1.22 +void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags)
    1.23 +{
    1.24 +	m_Listener = pCallbacks;
    1.25 +	m_Interval = fInterval;
    1.26 +	m_ToExec = fToExec;
    1.27 +	m_pData = pData;
    1.28 +	m_Flags = flags;
    1.29 +	m_InExec = false;
    1.30 +	m_KillMe = false;
    1.31 +}
    1.32 +
    1.33 +void CTimerSystem::OnSourceModAllInitialized()
    1.34 +{
    1.35 +	g_ShareSys.AddInterface(NULL, this);
    1.36 +}
    1.37 +
    1.38 +void CTimerSystem::RunFrame()
    1.39 +{
    1.40 +	ITimer *pTimer;
    1.41 +	TimerIter iter;
    1.42 +
    1.43 +	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
    1.44 +	{
    1.45 +		pTimer = (*iter);
    1.46 +		if (gpGlobals->curtime >= pTimer->m_ToExec)
    1.47 +		{
    1.48 +			pTimer->m_InExec = true;
    1.49 +			pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
    1.50 +			if (pTimer->m_KillMe)
    1.51 +			{
    1.52 +				pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
    1.53 +			}
    1.54 +			iter = m_SingleTimers.erase(iter);
    1.55 +			m_FreeTimers.push(pTimer);
    1.56 +		} else {
    1.57 +			break;
    1.58 +		}
    1.59 +	}
    1.60 +
    1.61 +	ResultType res;
    1.62 +	for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); )
    1.63 +	{
    1.64 +		pTimer = (*iter);
    1.65 +		if (gpGlobals->curtime >= pTimer->m_ToExec)
    1.66 +		{
    1.67 +			pTimer->m_InExec = true;
    1.68 +			res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
    1.69 +			if (pTimer->m_KillMe || (res == Pl_Stop))
    1.70 +			{
    1.71 +				pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
    1.72 +				iter = m_LoopTimers.erase(iter);
    1.73 +				m_FreeTimers.push(pTimer);
    1.74 +				continue;
    1.75 +			}
    1.76 +			pTimer->m_InExec = false;
    1.77 +			pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval;
    1.78 +		}
    1.79 +		iter++;
    1.80 +	}
    1.81 +
    1.82 +	m_LastExecTime = gpGlobals->curtime;
    1.83 +}
    1.84 +
    1.85 +ITimer *CTimerSystem::CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags)
    1.86 +{
    1.87 +	ITimer *pTimer;
    1.88 +	TimerIter iter;
    1.89 +	float to_exec = gpGlobals->curtime + fInterval;
    1.90 +
    1.91 +	if (m_FreeTimers.empty())
    1.92 +	{
    1.93 +		pTimer = new ITimer;
    1.94 +	} else {
    1.95 +		pTimer = m_FreeTimers.front();
    1.96 +		m_FreeTimers.pop();
    1.97 +	}
    1.98 +
    1.99 +	pTimer->Initialize(pCallbacks, fInterval, to_exec, pData, flags);
   1.100 +
   1.101 +	if (flags & TIMER_FLAG_REPEAT)
   1.102 +	{
   1.103 +		m_LoopTimers.push_back(pTimer);
   1.104 +		goto return_timer;
   1.105 +	}
   1.106 +
   1.107 +	if (m_SingleTimers.size() >= 1)
   1.108 +	{
   1.109 +		iter = --m_SingleTimers.end();
   1.110 +		if ((*iter)->m_ToExec <= to_exec)
   1.111 +		{
   1.112 +			goto insert_end;
   1.113 +		}
   1.114 +	}
   1.115 +
   1.116 +	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
   1.117 +	{
   1.118 +		if ((*iter)->m_ToExec >= to_exec)
   1.119 +		{
   1.120 +			m_SingleTimers.insert(iter, pTimer);
   1.121 +			goto return_timer;
   1.122 +		}
   1.123 +	}
   1.124 +
   1.125 +insert_end:
   1.126 +	m_SingleTimers.push_back(pTimer);
   1.127 +
   1.128 +return_timer:
   1.129 +	return pTimer;
   1.130 +}
   1.131 +
   1.132 +void CTimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec)
   1.133 +{
   1.134 +	ResultType res;
   1.135 +
   1.136 +	if (pTimer->m_InExec)
   1.137 +	{
   1.138 +		return;
   1.139 +	}
   1.140 +
   1.141 +	pTimer->m_InExec = true;
   1.142 +	res = pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
   1.143 +
   1.144 +	if (!(pTimer->m_Flags & TIMER_FLAG_REPEAT))
   1.145 +	{
   1.146 +		pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   1.147 +		m_SingleTimers.remove(pTimer);
   1.148 +		m_FreeTimers.push(pTimer);
   1.149 +	} else {
   1.150 +		if (delayExec && (res != Pl_Stop) && !pTimer->m_KillMe)
   1.151 +		{
   1.152 +			pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval;
   1.153 +			pTimer->m_InExec = false;
   1.154 +			return;
   1.155 +		}
   1.156 +		pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   1.157 +		m_LoopTimers.remove(pTimer);
   1.158 +		m_FreeTimers.push(pTimer);
   1.159 +	}
   1.160 +}
   1.161 +
   1.162 +void CTimerSystem::KillTimer(ITimer *pTimer)
   1.163 +{
   1.164 +	TimerList *pList;
   1.165 +
   1.166 +	if (pTimer->m_KillMe)
   1.167 +	{
   1.168 +		return;
   1.169 +	}
   1.170 +
   1.171 +	if (pTimer->m_InExec)
   1.172 +	{
   1.173 +		pTimer->m_KillMe = true;
   1.174 +		return;
   1.175 +	}
   1.176 +
   1.177 +	pTimer->m_InExec = true; /* The timer it's not really executed but this check needs to be done */
   1.178 +	pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
   1.179 +
   1.180 +	pList = (pTimer->m_Flags & TIMER_FLAG_REPEAT) ? &m_LoopTimers : &m_SingleTimers;
   1.181 +
   1.182 +	pList->remove(pTimer);
   1.183 +	m_FreeTimers.push(pTimer);
   1.184 +}
   1.185 +
   1.186 +void CTimerSystem::MapChange()
   1.187 +{
   1.188 +	ITimer *pTimer;
   1.189 +	TimerIter iter;
   1.190 +
   1.191 +	for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); iter++)
   1.192 +	{
   1.193 +		pTimer = (*iter);
   1.194 +		pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + gpGlobals->curtime;
   1.195 +	}
   1.196 +
   1.197 +	for (iter=m_LoopTimers.begin(); iter!=m_LoopTimers.end(); iter++)
   1.198 +	{
   1.199 +		pTimer = (*iter);
   1.200 +		pTimer->m_ToExec = pTimer->m_ToExec - m_LastExecTime + gpGlobals->curtime;
   1.201 +	}
   1.202 +}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/core/CTimerSys.h	Sat Mar 10 13:16:19 2007 +0000
     2.3 @@ -0,0 +1,65 @@
     2.4 +/**
     2.5 +* vim: set ts=4 :
     2.6 +* ===============================================================
     2.7 +* SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     2.8 +* ===============================================================
     2.9 +*
    2.10 +* This file is not open source and may not be copied without explicit
    2.11 +* written permission of AlliedModders LLC.  This file may not be redistributed 
    2.12 +* in whole or significant part.
    2.13 +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    2.14 +*
    2.15 +* Version: $Id$
    2.16 +*/
    2.17 +
    2.18 +#ifndef _INCLUDE_SOURCEMOD_CTIMERSYS_H_
    2.19 +#define _INCLUDE_SOURCEMOD_CTIMERSYS_H_
    2.20 +
    2.21 +#include "ShareSys.h"
    2.22 +#include <ITimerSystem.h>
    2.23 +#include <sh_stack.h>
    2.24 +#include <sh_list.h>
    2.25 +#include "sourcemm_api.h"
    2.26 +
    2.27 +using namespace SourceHook;
    2.28 +using namespace SourceMod;
    2.29 +
    2.30 +typedef List<ITimer *> TimerList;
    2.31 +typedef List<ITimer *>::iterator TimerIter;
    2.32 +
    2.33 +class SourceMod::ITimer
    2.34 +{
    2.35 +public:
    2.36 +	void Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec, void *pData, int flags);
    2.37 +	ITimedEvent *m_Listener;
    2.38 +	void *m_pData;
    2.39 +	float m_Interval;
    2.40 +	float m_ToExec;
    2.41 +	int m_Flags;
    2.42 +	bool m_InExec;
    2.43 +	bool m_KillMe;
    2.44 +};
    2.45 +
    2.46 +class CTimerSystem : 
    2.47 +	public ITimerSystem,
    2.48 +	public SMGlobalClass
    2.49 +{
    2.50 +public: //SMGlobalClass
    2.51 +	void OnSourceModAllInitialized();
    2.52 +public: //ITimerSystem
    2.53 +	ITimer *CreateTimer(ITimedEvent *pCallbacks, float fInterval, void *pData, int flags);
    2.54 +	void KillTimer(ITimer *pTimer);
    2.55 +	void FireTimerOnce(ITimer *pTimer, bool delayExec=false);
    2.56 +public:
    2.57 +	void RunFrame();
    2.58 +	void MapChange();
    2.59 +private:
    2.60 +	List<ITimer *> m_SingleTimers;
    2.61 +	List<ITimer *> m_LoopTimers;
    2.62 +	CStack<ITimer *> m_FreeTimers;
    2.63 +	float m_LastExecTime;
    2.64 +};
    2.65 +
    2.66 +extern CTimerSystem g_Timers;
    2.67 +
    2.68 +#endif //_INCLUDE_SOURCEMOD_CTIMERSYS_H_
     3.1 --- a/core/msvc8/sourcemod_mm.vcproj	Sat Mar 10 05:52:51 2007 +0000
     3.2 +++ b/core/msvc8/sourcemod_mm.vcproj	Sat Mar 10 13:16:19 2007 +0000
     3.3 @@ -1,7 +1,7 @@
     3.4  <?xml version="1.0" encoding="Windows-1252"?>
     3.5  <VisualStudioProject
     3.6  	ProjectType="Visual C++"
     3.7 -	Version="8.00"
     3.8 +	Version="8,00"
     3.9  	Name="sourcemod_mm"
    3.10  	ProjectGUID="{E39527CD-7CAB-4420-97CC-DA1B93B260BC}"
    3.11  	RootNamespace="sourcemod_mm"
    3.12 @@ -220,6 +220,10 @@
    3.13  				>
    3.14  			</File>
    3.15  			<File
    3.16 +				RelativePath="..\CTimerSys.cpp"
    3.17 +				>
    3.18 +			</File>
    3.19 +			<File
    3.20  				RelativePath="..\CTranslator.cpp"
    3.21  				>
    3.22  			</File>
    3.23 @@ -314,6 +318,10 @@
    3.24  				>
    3.25  			</File>
    3.26  			<File
    3.27 +				RelativePath="..\CTimerSys.h"
    3.28 +				>
    3.29 +			</File>
    3.30 +			<File
    3.31  				RelativePath="..\CTranslator.h"
    3.32  				>
    3.33  			</File>
    3.34 @@ -422,6 +430,10 @@
    3.35  				>
    3.36  			</File>
    3.37  			<File
    3.38 +				RelativePath="..\..\public\ITimerSystem.h"
    3.39 +				>
    3.40 +			</File>
    3.41 +			<File
    3.42  				RelativePath="..\..\public\IUserMessages.h"
    3.43  				>
    3.44  			</File>
     4.1 --- a/core/sourcemod.cpp	Sat Mar 10 05:52:51 2007 +0000
     4.2 +++ b/core/sourcemod.cpp	Sat Mar 10 13:16:19 2007 +0000
     4.3 @@ -26,6 +26,7 @@
     4.4  #include "CPlayerManager.h"
     4.5  #include "CTranslator.h"
     4.6  #include "ForwardSys.h"
     4.7 +#include "CTimerSys.h"
     4.8  
     4.9  SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
    4.10  SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
    4.11 @@ -193,6 +194,7 @@
    4.12  	g_LastAuthCheck = 0.0f;
    4.13  
    4.14  	g_Logger.MapChange(pMapName);
    4.15 +	g_Timers.MapChange();
    4.16  
    4.17  	/* Refresh language stuff */
    4.18  	char path[PLATFORM_MAX_PATH];
    4.19 @@ -221,7 +223,7 @@
    4.20  	 * precious CPU cycles.
    4.21  	 */
    4.22  	float curtime = gpGlobals->curtime;
    4.23 -	if (curtime - g_LastTime > 0.1f)
    4.24 +	if (curtime - g_LastTime >= 0.1f)
    4.25  	{
    4.26  		if (m_CheckingAuth
    4.27  			&& (gpGlobals->curtime - g_LastAuthCheck > 0.7f))
    4.28 @@ -229,9 +231,11 @@
    4.29  			g_LastAuthCheck = gpGlobals->curtime;
    4.30  			g_Players.RunAuthChecks();
    4.31  		}
    4.32 +
    4.33 +		g_Timers.RunFrame();
    4.34  		g_LastTime = curtime;
    4.35  	}
    4.36 -	
    4.37 +
    4.38  	if (g_pOnGameFrame && g_pOnGameFrame->GetFunctionCount())
    4.39  	{
    4.40  		g_pOnGameFrame->Execute(NULL);
     5.1 --- a/public/ITimerSystem.h	Sat Mar 10 05:52:51 2007 +0000
     5.2 +++ b/public/ITimerSystem.h	Sat Mar 10 13:16:19 2007 +0000
     5.3 @@ -20,11 +20,10 @@
     5.4  #define _INCLUDE_SOURCEMOD_TIMER_SYSTEM_H_
     5.5  
     5.6  #include <IShareSys.h>
     5.7 +#include <IForwardSys.h>
     5.8  
     5.9 -//:TODO: this is a placeholder and not yet implemented
    5.10 -//remove these lines and uncomment once we're done!
    5.11 -//#define SMINTERFACE_TIMERSYS_NAME		"ITimerSys"
    5.12 -//#define SMINTERFACE_TIMERSYS_VERSION	1
    5.13 +#define SMINTERFACE_TIMERSYS_NAME		"ITimerSys"
    5.14 +#define SMINTERFACE_TIMERSYS_VERSION	1
    5.15  
    5.16  namespace SourceMod
    5.17  {
    5.18 @@ -41,9 +40,7 @@
    5.19  		 *
    5.20  		 * @param pTimer		Pointer to the timer instance.
    5.21  		 * @param pData			Private pointer passed from host.
    5.22 -		 * @return				Pl_Handle to stop timer, Pl_Continue to continue.
    5.23 -		 *						Passing Pl_Continue when a timer's repeat count
    5.24 -		 *						has been exhausted will not extend it.
    5.25 +		 * @return				Pl_Stop to stop timer, Pl_Continue to continue.
    5.26  		 */
    5.27  		virtual ResultType OnTimer(ITimer *pTimer, void *pData) =0;
    5.28  
    5.29 @@ -53,7 +50,7 @@
    5.30  		 * @param pTimer		Pointer to the timer instance.
    5.31  		 * @param pData			Private data pointer passed from host.
    5.32  		 */
    5.33 -		virtual void OnTimerEnd() =0;
    5.34 +		virtual void OnTimerEnd(ITimer *pTimer, void *pData) =0;
    5.35  	};
    5.36  
    5.37  	#define TIMER_FLAG_REPEAT		(1<<0)