implemented timer natives
authorBorja Ferrer <faluco@alliedmods.net>
Wed Mar 14 11:34:03 2007 +0000 (2007-03-14)
changeset 612e000559527a3
parent 611 9921680863d4
child 613 b2d326c6d46e
implemented timer natives
fixed some design issues in the timer manager
core/TimerSys.cpp
core/msvc8/sourcemod_mm.vcproj
core/smn_timers.cpp
plugins/include/timers.inc
     1.1 --- a/core/TimerSys.cpp	Wed Mar 14 07:54:54 2007 +0000
     1.2 +++ b/core/TimerSys.cpp	Wed Mar 14 11:34:03 2007 +0000
     1.3 @@ -44,10 +44,7 @@
     1.4  		{
     1.5  			pTimer->m_InExec = true;
     1.6  			pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData);
     1.7 -			if (pTimer->m_KillMe)
     1.8 -			{
     1.9 -				pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
    1.10 -			}
    1.11 +			pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData);
    1.12  			iter = m_SingleTimers.erase(iter);
    1.13  			m_FreeTimers.push(pTimer);
    1.14  		} else {
    1.15 @@ -144,9 +141,12 @@
    1.16  		m_SingleTimers.remove(pTimer);
    1.17  		m_FreeTimers.push(pTimer);
    1.18  	} else {
    1.19 -		if (delayExec && (res != Pl_Stop) && !pTimer->m_KillMe)
    1.20 +		if ((res != Pl_Stop) && !pTimer->m_KillMe)
    1.21  		{
    1.22 -			pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval;
    1.23 +			if (delayExec)
    1.24 +			{
    1.25 +				pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval;
    1.26 +			}
    1.27  			pTimer->m_InExec = false;
    1.28  			return;
    1.29  		}
     2.1 --- a/core/msvc8/sourcemod_mm.vcproj	Wed Mar 14 07:54:54 2007 +0000
     2.2 +++ b/core/msvc8/sourcemod_mm.vcproj	Wed Mar 14 11:34:03 2007 +0000
     2.3 @@ -754,6 +754,10 @@
     2.4  				>
     2.5  			</File>
     2.6  			<File
     2.7 +				RelativePath="..\smn_timers.cpp"
     2.8 +				>
     2.9 +			</File>
    2.10 +			<File
    2.11  				RelativePath="..\smn_usermsgs.cpp"
    2.12  				>
    2.13  			</File>
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/core/smn_timers.cpp	Wed Mar 14 11:34:03 2007 +0000
     3.3 @@ -0,0 +1,222 @@
     3.4 +/**
     3.5 +* ===============================================================
     3.6 +* SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     3.7 +* ===============================================================
     3.8 +*
     3.9 +* This file is not open source and may not be copied without explicit
    3.10 +* written permission of AlliedModders LLC.  This file may not be redistributed 
    3.11 +* in whole or significant part.
    3.12 +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    3.13 +*
    3.14 +* Version: $Id$
    3.15 +*/
    3.16 +
    3.17 +#include "HandleSys.h"
    3.18 +#include "TimerSys.h"
    3.19 +#include "Logger.h"
    3.20 +
    3.21 +#define TIMER_HNDL_CLOSE	(1<<9)
    3.22 +
    3.23 +HandleType_t g_TimerType;
    3.24 +
    3.25 +struct TimerInfo 
    3.26 +{
    3.27 +	ITimer *Timer;
    3.28 +	IPluginFunction *Hook;
    3.29 +	IPluginContext *pContext;
    3.30 +	Handle_t TimerHandle;
    3.31 +	int UserData;
    3.32 +	int Flags;
    3.33 +};
    3.34 +
    3.35 +class TimerNatives :
    3.36 +	public SMGlobalClass,
    3.37 +	public IHandleTypeDispatch,
    3.38 +	public ITimedEvent
    3.39 +{
    3.40 +public: //ITimedEvent
    3.41 +	ResultType OnTimer(ITimer *pTimer, void *pData);
    3.42 +	void OnTimerEnd(ITimer *pTimer, void *pData);
    3.43 +public: //IHandleTypeDispatch
    3.44 +	void OnHandleDestroy(HandleType_t type, void *object);
    3.45 +public: //SMGlobalClass
    3.46 +	void OnSourceModAllInitialized();
    3.47 +	void OnSourceModShutdown();
    3.48 +public:
    3.49 +	TimerInfo *CreateTimerInfo();
    3.50 +	void DeleteTimerInfo(TimerInfo *pInfo);
    3.51 +private:
    3.52 +	CStack<TimerInfo *> m_FreeTimers;
    3.53 +};
    3.54 +
    3.55 +void TimerNatives::OnSourceModAllInitialized()
    3.56 +{
    3.57 +	HandleAccess sec;
    3.58 +	sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
    3.59 +
    3.60 +	g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    3.61 +}
    3.62 +
    3.63 +void TimerNatives::OnSourceModShutdown()
    3.64 +{
    3.65 +	g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent);
    3.66 +	g_TimerType = 0;
    3.67 +}
    3.68 +
    3.69 +void TimerNatives::OnHandleDestroy(HandleType_t type, void *object)
    3.70 +{
    3.71 +	TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object);
    3.72 +
    3.73 +	g_Timers.KillTimer(pTimer->Timer);
    3.74 +}
    3.75 +
    3.76 +TimerInfo *TimerNatives::CreateTimerInfo()
    3.77 +{
    3.78 +	TimerInfo *pInfo;
    3.79 +
    3.80 +	if (m_FreeTimers.empty())
    3.81 +	{
    3.82 +		pInfo = new TimerInfo;
    3.83 +	} else {
    3.84 +		pInfo = m_FreeTimers.front();
    3.85 +		m_FreeTimers.pop();
    3.86 +	}
    3.87 +
    3.88 +	return pInfo;
    3.89 +}
    3.90 +
    3.91 +void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo)
    3.92 +{
    3.93 +	m_FreeTimers.push(pInfo);
    3.94 +}
    3.95 +
    3.96 +ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData)
    3.97 +{
    3.98 +	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
    3.99 +	IPluginFunction *pFunc = pInfo->Hook;
   3.100 +	cell_t res = static_cast<ResultType>(Pl_Continue);
   3.101 +
   3.102 +	pFunc->PushCell(pInfo->TimerHandle);
   3.103 +	pFunc->PushCell(pInfo->UserData);
   3.104 +	pFunc->Execute(&res);
   3.105 +
   3.106 +	return static_cast<ResultType>(res);
   3.107 +}
   3.108 +
   3.109 +void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData)
   3.110 +{
   3.111 +	HandleSecurity sec;
   3.112 +	HandleError herr;
   3.113 +	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
   3.114 +	Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData);
   3.115 +
   3.116 +	sec.pOwner = pInfo->pContext->GetIdentity();
   3.117 +	sec.pIdentity = g_pCoreIdent;
   3.118 +
   3.119 +	if (pInfo->Flags & TIMER_HNDL_CLOSE)
   3.120 +	{
   3.121 +		if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None)
   3.122 +		{
   3.123 +			g_Logger.LogError("Invalid data handle %x (error %d) passed during timer end", usrhndl, herr);
   3.124 +		}
   3.125 +	}
   3.126 +
   3.127 +	g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec);
   3.128 +}
   3.129 +
   3.130 +/*******************************
   3.131 +*                              *
   3.132 +* TIMER NATIVE IMPLEMENTATIONS *
   3.133 +*                              *
   3.134 +********************************/
   3.135 +
   3.136 +static TimerNatives s_TimerNatives;
   3.137 +
   3.138 +static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params)
   3.139 +{
   3.140 +	IPluginFunction *pFunc;
   3.141 +	TimerInfo *pInfo;
   3.142 +	ITimer *pTimer;
   3.143 +	Handle_t hndl;
   3.144 +	int flags = params[4];
   3.145 +
   3.146 +	pFunc = pCtx->GetFunctionById(params[2]);
   3.147 +	if (!pFunc)
   3.148 +	{
   3.149 +		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   3.150 +	}
   3.151 +
   3.152 +	pInfo = s_TimerNatives.CreateTimerInfo();
   3.153 +	pTimer = g_Timers.CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags);
   3.154 +	hndl = g_HandleSys.CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   3.155 +
   3.156 +	pInfo->UserData = params[3];
   3.157 +	pInfo->Flags = flags;
   3.158 +	pInfo->TimerHandle = hndl;
   3.159 +	pInfo->Hook = pFunc;
   3.160 +	pInfo->Timer = pTimer;
   3.161 +	pInfo->pContext = pCtx;
   3.162 +
   3.163 +	return hndl;
   3.164 +}
   3.165 +
   3.166 +static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params)
   3.167 +{
   3.168 +	Handle_t hndl = static_cast<Handle_t>(params[1]);
   3.169 +	HandleError herr;
   3.170 +	HandleSecurity sec;
   3.171 +	TimerInfo *pInfo;
   3.172 +
   3.173 +	sec.pOwner = NULL;
   3.174 +	sec.pIdentity = g_pCoreIdent;
   3.175 +
   3.176 +	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   3.177 +		!= HandleError_None)
   3.178 +	{
   3.179 +		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   3.180 +	}
   3.181 +
   3.182 +	g_Timers.KillTimer(pInfo->Timer);
   3.183 +
   3.184 +	if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE))
   3.185 +	{
   3.186 +		sec.pOwner = pInfo->pContext->GetIdentity();
   3.187 +		sec.pIdentity = g_pCoreIdent;
   3.188 +
   3.189 +		if ((herr=g_HandleSys.FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None)
   3.190 +		{
   3.191 +			return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr);
   3.192 +		}
   3.193 +	}
   3.194 +
   3.195 +	return 1;
   3.196 +}
   3.197 +
   3.198 +static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params)
   3.199 +{
   3.200 +	Handle_t hndl = static_cast<Handle_t>(params[1]);
   3.201 +	HandleError herr;
   3.202 +	HandleSecurity sec;
   3.203 +	TimerInfo *pInfo;
   3.204 +
   3.205 +	sec.pOwner = NULL;
   3.206 +	sec.pIdentity = g_pCoreIdent;
   3.207 +
   3.208 +	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   3.209 +		!= HandleError_None)
   3.210 +	{
   3.211 +		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   3.212 +	}
   3.213 +
   3.214 +	g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false);
   3.215 +
   3.216 +	return 1;
   3.217 +}
   3.218 +
   3.219 +REGISTER_NATIVES(timernatives)
   3.220 +{
   3.221 +	{"CreateTimer",				smn_CreateTimer},
   3.222 +	{"KillTimer",				smn_KillTimer},
   3.223 +	{"TriggerTimer",			smn_TriggerTimer},
   3.224 +	{NULL,						NULL}
   3.225 +};
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/plugins/include/timers.inc	Wed Mar 14 11:34:03 2007 +0000
     4.3 @@ -0,0 +1,107 @@
     4.4 +/**
     4.5 + * vim: set ts=4 :
     4.6 + * ===============================================================
     4.7 + * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     4.8 + * ===============================================================
     4.9 + *
    4.10 + *  This file is part of the SourceMod/SourcePawn SDK.  This file may only be used 
    4.11 + * or modified under the Terms and Conditions of its License Agreement, which is found 
    4.12 + * in LICENSE.txt.  The Terms and Conditions for making SourceMod extensions/plugins 
    4.13 + * may change at any time.  To view the latest information, see:
    4.14 + *   http://www.sourcemod.net/license.php
    4.15 + *
    4.16 + * Version: $Id$
    4.17 + */
    4.18 +
    4.19 +#if defined _timers_included
    4.20 + #endinput
    4.21 +#endif
    4.22 +#define _timers_included
    4.23 +
    4.24 +#include <datapack>
    4.25 +
    4.26 +#define TIMER_REPEAT		(1<<0)		/**< Timer will repeat until it returns Plugin_Stop */
    4.27 +#define TIMER_HNDL_CLOSE	(1<<9)		/**< Timer will automatically call CloseHandle() on its value when finished */
    4.28 +
    4.29 +/**
    4.30 + * Any of the following prototypes will work for a timed function.
    4.31 + */
    4.32 +funcenum Timer
    4.33 +{
    4.34 +	/**
    4.35 + 	 * Called when the timer interval has elapsed.
    4.36 + 	 * 
    4.37 + 	 * @param timer			Handle to the timer object.
    4.38 + 	 * @param hndl			Handle passed when the timer was created.
    4.39 + 	 * @return				Plugin_Stop to stop a repeating timer, any other value for
    4.40 + 	 *						default behavior.
    4.41 + 	 */
    4.42 +	Action:public(Handle:timer, Handle:hndl),
    4.43 +	
    4.44 +	/**
    4.45 + 	 * Called when the timer interval has elapsed.
    4.46 + 	 * 
    4.47 + 	 * @param timer			Handle to the timer object.
    4.48 + 	 * @param value			Value passed when the timer was created.
    4.49 + 	 * @return				Plugin_Stop to stop a repeating timer, any other value for
    4.50 + 	 *						default behavior.
    4.51 + 	 */
    4.52 +	Action:public(Handle:timer, value),
    4.53 +	
    4.54 +	/**
    4.55 + 	 * Called when the timer interval has elapsed.
    4.56 + 	 * 
    4.57 + 	 * @param timer			Handle to the timer object.
    4.58 + 	 * @return				Plugin_Stop to stop a repeating timer, any other value for
    4.59 + 	 *						default behavior.
    4.60 + 	 */
    4.61 +	Action:public(Handle:timer),
    4.62 +};
    4.63 +
    4.64 +/**
    4.65 + * Creates a basic timer.  Calling CloseHandle() on a timer will end the timer.
    4.66 + *
    4.67 + * @param interval			Interval from the current game time to execute the given function.
    4.68 + * @param func				Function to execute once the given interval has elapsed.
    4.69 + * @param value				Handle or value to give to the timer function.
    4.70 + * @param flags				Flags to set (such as repeatability or auto-Handle closing).
    4.71 + * @return					Handle to the timer object.  You do not need to call CloseHandle().
    4.72 + */
    4.73 +native Handle:CreateTimer(Float:interval, Timer:func, {Handle,_}:value, flags);
    4.74 +
    4.75 +/**
    4.76 + * Kills a timer.  Use this instead of CloseHandle() if you need more options.
    4.77 + *
    4.78 + * @param autoClose			If autoClose is true, the timer's value will be 
    4.79 + *							closed as a handle if TIMER_HNDL_CLOSE was not specified.
    4.80 + * @noreturn
    4.81 + */
    4.82 +native KillTimer(Handle:timer, bool:autoClose=false);
    4.83 +
    4.84 +/**
    4.85 + * Manually triggers a timer so its function will be called.
    4.86 + *
    4.87 + * @param timer				Timer Handle to trigger.
    4.88 + * @param reset				If reset is true, the elapsed time counter is reset
    4.89 + *							so the full interval must pass again.
    4.90 + * @noreturn
    4.91 + */
    4.92 +native TriggerTimer(Handle:timer, bool:reset=false);
    4.93 +
    4.94 +/**
    4.95 + * Creates a timer associated with a new data pack, and returns the datapack.
    4.96 + * @note The datapack is automatically freed when the timer ends.
    4.97 + * @note The position of the datapack is not reset or changed for the timer function.
    4.98 + *
    4.99 + * @param interval			Interval from the current game time to execute the given function.
   4.100 + * @param func				Function to execute once the given interval has elapsed.
   4.101 + * @param data				The newly created datapack is passed though this by-reference parameter.
   4.102 + * @param flags				Timer flags.
   4.103 + * @return					Handle to the timer object.  You do not need to call CloseHandle().
   4.104 + */
   4.105 +stock Handle:CreateDataTimer(Float:interval, Timer:func, &Handle:data, flags)
   4.106 +{
   4.107 +	data = CreateDataPack();
   4.108 +	flags |= TIMER_HNDL_CLOSE;
   4.109 +	return CreateTimer(interval, func, data, flags);
   4.110 +}