implemented timer natives
fixed some design issues in the timer manager --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40618
This commit is contained in:
		
							parent
							
								
									62aa55b23b
								
							
						
					
					
						commit
						971cb8f7e7
					
				| @ -44,10 +44,7 @@ void CTimerSystem::RunFrame() | |||||||
| 		{ | 		{ | ||||||
| 			pTimer->m_InExec = true; | 			pTimer->m_InExec = true; | ||||||
| 			pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); | 			pTimer->m_Listener->OnTimer(pTimer, pTimer->m_pData); | ||||||
| 			if (pTimer->m_KillMe) |  | ||||||
| 			{ |  | ||||||
| 			pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); | 			pTimer->m_Listener->OnTimerEnd(pTimer, pTimer->m_pData); | ||||||
| 			} |  | ||||||
| 			iter = m_SingleTimers.erase(iter); | 			iter = m_SingleTimers.erase(iter); | ||||||
| 			m_FreeTimers.push(pTimer); | 			m_FreeTimers.push(pTimer); | ||||||
| 		} else { | 		} else { | ||||||
| @ -144,9 +141,12 @@ void CTimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) | |||||||
| 		m_SingleTimers.remove(pTimer); | 		m_SingleTimers.remove(pTimer); | ||||||
| 		m_FreeTimers.push(pTimer); | 		m_FreeTimers.push(pTimer); | ||||||
| 	} else { | 	} else { | ||||||
| 		if (delayExec && (res != Pl_Stop) && !pTimer->m_KillMe) | 		if ((res != Pl_Stop) && !pTimer->m_KillMe) | ||||||
|  | 		{ | ||||||
|  | 			if (delayExec) | ||||||
| 			{ | 			{ | ||||||
| 				pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval; | 				pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval; | ||||||
|  | 			} | ||||||
| 			pTimer->m_InExec = false; | 			pTimer->m_InExec = false; | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -753,6 +753,10 @@ | |||||||
| 				RelativePath="..\smn_textparse.cpp" | 				RelativePath="..\smn_textparse.cpp" | ||||||
| 				> | 				> | ||||||
| 			</File> | 			</File> | ||||||
|  | 			<File | ||||||
|  | 				RelativePath="..\smn_timers.cpp" | ||||||
|  | 				> | ||||||
|  | 			</File> | ||||||
| 			<File | 			<File | ||||||
| 				RelativePath="..\smn_usermsgs.cpp" | 				RelativePath="..\smn_usermsgs.cpp" | ||||||
| 				> | 				> | ||||||
|  | |||||||
							
								
								
									
										222
									
								
								core/smn_timers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								core/smn_timers.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,222 @@ | |||||||
|  | /**
 | ||||||
|  | * =============================================================== | ||||||
|  | * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved. | ||||||
|  | * =============================================================== | ||||||
|  | * | ||||||
|  | * This file is not open source and may not be copied without explicit | ||||||
|  | * written permission of AlliedModders LLC.  This file may not be redistributed  | ||||||
|  | * in whole or significant part. | ||||||
|  | * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
 | ||||||
|  | * | ||||||
|  | * Version: $Id$ | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #include "HandleSys.h" | ||||||
|  | #include "TimerSys.h" | ||||||
|  | #include "Logger.h" | ||||||
|  | 
 | ||||||
|  | #define TIMER_HNDL_CLOSE	(1<<9) | ||||||
|  | 
 | ||||||
|  | HandleType_t g_TimerType; | ||||||
|  | 
 | ||||||
|  | struct TimerInfo  | ||||||
|  | { | ||||||
|  | 	ITimer *Timer; | ||||||
|  | 	IPluginFunction *Hook; | ||||||
|  | 	IPluginContext *pContext; | ||||||
|  | 	Handle_t TimerHandle; | ||||||
|  | 	int UserData; | ||||||
|  | 	int Flags; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class TimerNatives : | ||||||
|  | 	public SMGlobalClass, | ||||||
|  | 	public IHandleTypeDispatch, | ||||||
|  | 	public ITimedEvent | ||||||
|  | { | ||||||
|  | public: //ITimedEvent
 | ||||||
|  | 	ResultType OnTimer(ITimer *pTimer, void *pData); | ||||||
|  | 	void OnTimerEnd(ITimer *pTimer, void *pData); | ||||||
|  | public: //IHandleTypeDispatch
 | ||||||
|  | 	void OnHandleDestroy(HandleType_t type, void *object); | ||||||
|  | public: //SMGlobalClass
 | ||||||
|  | 	void OnSourceModAllInitialized(); | ||||||
|  | 	void OnSourceModShutdown(); | ||||||
|  | public: | ||||||
|  | 	TimerInfo *CreateTimerInfo(); | ||||||
|  | 	void DeleteTimerInfo(TimerInfo *pInfo); | ||||||
|  | private: | ||||||
|  | 	CStack<TimerInfo *> m_FreeTimers; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void TimerNatives::OnSourceModAllInitialized() | ||||||
|  | { | ||||||
|  | 	HandleAccess sec; | ||||||
|  | 	sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY; | ||||||
|  | 
 | ||||||
|  | 	g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TimerNatives::OnSourceModShutdown() | ||||||
|  | { | ||||||
|  | 	g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent); | ||||||
|  | 	g_TimerType = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TimerNatives::OnHandleDestroy(HandleType_t type, void *object) | ||||||
|  | { | ||||||
|  | 	TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object); | ||||||
|  | 
 | ||||||
|  | 	g_Timers.KillTimer(pTimer->Timer); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | TimerInfo *TimerNatives::CreateTimerInfo() | ||||||
|  | { | ||||||
|  | 	TimerInfo *pInfo; | ||||||
|  | 
 | ||||||
|  | 	if (m_FreeTimers.empty()) | ||||||
|  | 	{ | ||||||
|  | 		pInfo = new TimerInfo; | ||||||
|  | 	} else { | ||||||
|  | 		pInfo = m_FreeTimers.front(); | ||||||
|  | 		m_FreeTimers.pop(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return pInfo; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo) | ||||||
|  | { | ||||||
|  | 	m_FreeTimers.push(pInfo); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData) | ||||||
|  | { | ||||||
|  | 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData); | ||||||
|  | 	IPluginFunction *pFunc = pInfo->Hook; | ||||||
|  | 	cell_t res = static_cast<ResultType>(Pl_Continue); | ||||||
|  | 
 | ||||||
|  | 	pFunc->PushCell(pInfo->TimerHandle); | ||||||
|  | 	pFunc->PushCell(pInfo->UserData); | ||||||
|  | 	pFunc->Execute(&res); | ||||||
|  | 
 | ||||||
|  | 	return static_cast<ResultType>(res); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData) | ||||||
|  | { | ||||||
|  | 	HandleSecurity sec; | ||||||
|  | 	HandleError herr; | ||||||
|  | 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData); | ||||||
|  | 	Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData); | ||||||
|  | 
 | ||||||
|  | 	sec.pOwner = pInfo->pContext->GetIdentity(); | ||||||
|  | 	sec.pIdentity = g_pCoreIdent; | ||||||
|  | 
 | ||||||
|  | 	if (pInfo->Flags & TIMER_HNDL_CLOSE) | ||||||
|  | 	{ | ||||||
|  | 		if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None) | ||||||
|  | 		{ | ||||||
|  | 			g_Logger.LogError("Invalid data handle %x (error %d) passed during timer end", usrhndl, herr); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*******************************
 | ||||||
|  | *                              * | ||||||
|  | * TIMER NATIVE IMPLEMENTATIONS * | ||||||
|  | *                              * | ||||||
|  | ********************************/ | ||||||
|  | 
 | ||||||
|  | static TimerNatives s_TimerNatives; | ||||||
|  | 
 | ||||||
|  | static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params) | ||||||
|  | { | ||||||
|  | 	IPluginFunction *pFunc; | ||||||
|  | 	TimerInfo *pInfo; | ||||||
|  | 	ITimer *pTimer; | ||||||
|  | 	Handle_t hndl; | ||||||
|  | 	int flags = params[4]; | ||||||
|  | 
 | ||||||
|  | 	pFunc = pCtx->GetFunctionById(params[2]); | ||||||
|  | 	if (!pFunc) | ||||||
|  | 	{ | ||||||
|  | 		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	pInfo = s_TimerNatives.CreateTimerInfo(); | ||||||
|  | 	pTimer = g_Timers.CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags); | ||||||
|  | 	hndl = g_HandleSys.CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL); | ||||||
|  | 
 | ||||||
|  | 	pInfo->UserData = params[3]; | ||||||
|  | 	pInfo->Flags = flags; | ||||||
|  | 	pInfo->TimerHandle = hndl; | ||||||
|  | 	pInfo->Hook = pFunc; | ||||||
|  | 	pInfo->Timer = pTimer; | ||||||
|  | 	pInfo->pContext = pCtx; | ||||||
|  | 
 | ||||||
|  | 	return hndl; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params) | ||||||
|  | { | ||||||
|  | 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||||
|  | 	HandleError herr; | ||||||
|  | 	HandleSecurity sec; | ||||||
|  | 	TimerInfo *pInfo; | ||||||
|  | 
 | ||||||
|  | 	sec.pOwner = NULL; | ||||||
|  | 	sec.pIdentity = g_pCoreIdent; | ||||||
|  | 
 | ||||||
|  | 	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo)) | ||||||
|  | 		!= HandleError_None) | ||||||
|  | 	{ | ||||||
|  | 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	g_Timers.KillTimer(pInfo->Timer); | ||||||
|  | 
 | ||||||
|  | 	if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE)) | ||||||
|  | 	{ | ||||||
|  | 		sec.pOwner = pInfo->pContext->GetIdentity(); | ||||||
|  | 		sec.pIdentity = g_pCoreIdent; | ||||||
|  | 
 | ||||||
|  | 		if ((herr=g_HandleSys.FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None) | ||||||
|  | 		{ | ||||||
|  | 			return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params) | ||||||
|  | { | ||||||
|  | 	Handle_t hndl = static_cast<Handle_t>(params[1]); | ||||||
|  | 	HandleError herr; | ||||||
|  | 	HandleSecurity sec; | ||||||
|  | 	TimerInfo *pInfo; | ||||||
|  | 
 | ||||||
|  | 	sec.pOwner = NULL; | ||||||
|  | 	sec.pIdentity = g_pCoreIdent; | ||||||
|  | 
 | ||||||
|  | 	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo)) | ||||||
|  | 		!= HandleError_None) | ||||||
|  | 	{ | ||||||
|  | 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false); | ||||||
|  | 
 | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | REGISTER_NATIVES(timernatives) | ||||||
|  | { | ||||||
|  | 	{"CreateTimer",				smn_CreateTimer}, | ||||||
|  | 	{"KillTimer",				smn_KillTimer}, | ||||||
|  | 	{"TriggerTimer",			smn_TriggerTimer}, | ||||||
|  | 	{NULL,						NULL} | ||||||
|  | }; | ||||||
							
								
								
									
										107
									
								
								plugins/include/timers.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								plugins/include/timers.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | |||||||
|  | /** | ||||||
|  |  * vim: set ts=4 : | ||||||
|  |  * =============================================================== | ||||||
|  |  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved. | ||||||
|  |  * =============================================================== | ||||||
|  |  * | ||||||
|  |  *  This file is part of the SourceMod/SourcePawn SDK.  This file may only be used  | ||||||
|  |  * or modified under the Terms and Conditions of its License Agreement, which is found  | ||||||
|  |  * in LICENSE.txt.  The Terms and Conditions for making SourceMod extensions/plugins  | ||||||
|  |  * may change at any time.  To view the latest information, see: | ||||||
|  |  *   http://www.sourcemod.net/license.php | ||||||
|  |  * | ||||||
|  |  * Version: $Id$ | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #if defined _timers_included
 | ||||||
|  |  #endinput
 | ||||||
|  | #endif
 | ||||||
|  | #define _timers_included
 | ||||||
|  | 
 | ||||||
|  | #include <datapack>
 | ||||||
|  | 
 | ||||||
|  | #define TIMER_REPEAT		(1<<0)		/**< Timer will repeat until it returns Plugin_Stop */
 | ||||||
|  | #define TIMER_HNDL_CLOSE	(1<<9)		/**< Timer will automatically call CloseHandle() on its value when finished */
 | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Any of the following prototypes will work for a timed function. | ||||||
|  |  */ | ||||||
|  | funcenum Timer | ||||||
|  | { | ||||||
|  | 	/** | ||||||
|  |  	 * Called when the timer interval has elapsed. | ||||||
|  |  	 *  | ||||||
|  |  	 * @param timer			Handle to the timer object. | ||||||
|  |  	 * @param hndl			Handle passed when the timer was created. | ||||||
|  |  	 * @return				Plugin_Stop to stop a repeating timer, any other value for | ||||||
|  |  	 *						default behavior. | ||||||
|  |  	 */ | ||||||
|  | 	Action:public(Handle:timer, Handle:hndl), | ||||||
|  | 	 | ||||||
|  | 	/** | ||||||
|  |  	 * Called when the timer interval has elapsed. | ||||||
|  |  	 *  | ||||||
|  |  	 * @param timer			Handle to the timer object. | ||||||
|  |  	 * @param value			Value passed when the timer was created. | ||||||
|  |  	 * @return				Plugin_Stop to stop a repeating timer, any other value for | ||||||
|  |  	 *						default behavior. | ||||||
|  |  	 */ | ||||||
|  | 	Action:public(Handle:timer, value), | ||||||
|  | 	 | ||||||
|  | 	/** | ||||||
|  |  	 * Called when the timer interval has elapsed. | ||||||
|  |  	 *  | ||||||
|  |  	 * @param timer			Handle to the timer object. | ||||||
|  |  	 * @return				Plugin_Stop to stop a repeating timer, any other value for | ||||||
|  |  	 *						default behavior. | ||||||
|  |  	 */ | ||||||
|  | 	Action:public(Handle:timer), | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Creates a basic timer.  Calling CloseHandle() on a timer will end the timer. | ||||||
|  |  * | ||||||
|  |  * @param interval			Interval from the current game time to execute the given function. | ||||||
|  |  * @param func				Function to execute once the given interval has elapsed. | ||||||
|  |  * @param value				Handle or value to give to the timer function. | ||||||
|  |  * @param flags				Flags to set (such as repeatability or auto-Handle closing). | ||||||
|  |  * @return					Handle to the timer object.  You do not need to call CloseHandle(). | ||||||
|  |  */ | ||||||
|  | native Handle:CreateTimer(Float:interval, Timer:func, {Handle,_}:value, flags); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Kills a timer.  Use this instead of CloseHandle() if you need more options. | ||||||
|  |  * | ||||||
|  |  * @param autoClose			If autoClose is true, the timer's value will be  | ||||||
|  |  *							closed as a handle if TIMER_HNDL_CLOSE was not specified. | ||||||
|  |  * @noreturn | ||||||
|  |  */ | ||||||
|  | native KillTimer(Handle:timer, bool:autoClose=false); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Manually triggers a timer so its function will be called. | ||||||
|  |  * | ||||||
|  |  * @param timer				Timer Handle to trigger. | ||||||
|  |  * @param reset				If reset is true, the elapsed time counter is reset | ||||||
|  |  *							so the full interval must pass again. | ||||||
|  |  * @noreturn | ||||||
|  |  */ | ||||||
|  | native TriggerTimer(Handle:timer, bool:reset=false); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Creates a timer associated with a new data pack, and returns the datapack. | ||||||
|  |  * @note The datapack is automatically freed when the timer ends. | ||||||
|  |  * @note The position of the datapack is not reset or changed for the timer function. | ||||||
|  |  * | ||||||
|  |  * @param interval			Interval from the current game time to execute the given function. | ||||||
|  |  * @param func				Function to execute once the given interval has elapsed. | ||||||
|  |  * @param data				The newly created datapack is passed though this by-reference parameter. | ||||||
|  |  * @param flags				Timer flags. | ||||||
|  |  * @return					Handle to the timer object.  You do not need to call CloseHandle(). | ||||||
|  |  */ | ||||||
|  | stock Handle:CreateDataTimer(Float:interval, Timer:func, &Handle:data, flags) | ||||||
|  | { | ||||||
|  | 	data = CreateDataPack(); | ||||||
|  | 	flags |= TIMER_HNDL_CLOSE; | ||||||
|  | 	return CreateTimer(interval, func, data, flags); | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user