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_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); | ||||
| 			m_FreeTimers.push(pTimer); | ||||
| 		} else { | ||||
| @ -144,9 +141,12 @@ void CTimerSystem::FireTimerOnce(ITimer *pTimer, bool delayExec) | ||||
| 		m_SingleTimers.remove(pTimer); | ||||
| 		m_FreeTimers.push(pTimer); | ||||
| 	} else { | ||||
| 		if (delayExec && (res != Pl_Stop) && !pTimer->m_KillMe) | ||||
| 		if ((res != Pl_Stop) && !pTimer->m_KillMe) | ||||
| 		{ | ||||
| 			pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval; | ||||
| 			if (delayExec) | ||||
| 			{ | ||||
| 				pTimer->m_ToExec = gpGlobals->curtime + pTimer->m_Interval; | ||||
| 			} | ||||
| 			pTimer->m_InExec = false; | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| @ -753,6 +753,10 @@ | ||||
| 				RelativePath="..\smn_textparse.cpp" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\smn_timers.cpp" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				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