core/smn_timers.cpp
author David Anderson <dvander@alliedmods.net>
Thu Mar 15 04:45:33 2007 +0000 (2007-03-15)
changeset 617 dc7671b320e4
parent 613 b2d326c6d46e
child 641 ce1f369ba889
permissions -rw-r--r--
fixed two spelling mistakes
     1 /**
     2 * ===============================================================
     3 * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     4 * ===============================================================
     5 *
     6 * This file is not open source and may not be copied without explicit
     7 * written permission of AlliedModders LLC.  This file may not be redistributed 
     8 * in whole or significant part.
     9 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    10 *
    11 * Version: $Id$
    12 */
    13 
    14 #include "HandleSys.h"
    15 #include "TimerSys.h"
    16 #include "Logger.h"
    17 
    18 #define TIMER_HNDL_CLOSE	(1<<9)
    19 
    20 HandleType_t g_TimerType;
    21 
    22 struct TimerInfo 
    23 {
    24 	ITimer *Timer;
    25 	IPluginFunction *Hook;
    26 	IPluginContext *pContext;
    27 	Handle_t TimerHandle;
    28 	int UserData;
    29 	int Flags;
    30 };
    31 
    32 class TimerNatives :
    33 	public SMGlobalClass,
    34 	public IHandleTypeDispatch,
    35 	public ITimedEvent
    36 {
    37 public: //ITimedEvent
    38 	ResultType OnTimer(ITimer *pTimer, void *pData);
    39 	void OnTimerEnd(ITimer *pTimer, void *pData);
    40 public: //IHandleTypeDispatch
    41 	void OnHandleDestroy(HandleType_t type, void *object);
    42 public: //SMGlobalClass
    43 	void OnSourceModAllInitialized();
    44 	void OnSourceModShutdown();
    45 public:
    46 	TimerInfo *CreateTimerInfo();
    47 	void DeleteTimerInfo(TimerInfo *pInfo);
    48 private:
    49 	CStack<TimerInfo *> m_FreeTimers;
    50 };
    51 
    52 void TimerNatives::OnSourceModAllInitialized()
    53 {
    54 	HandleAccess sec;
    55 	sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
    56 
    57 	g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    58 }
    59 
    60 void TimerNatives::OnSourceModShutdown()
    61 {
    62 	g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent);
    63 	g_TimerType = 0;
    64 }
    65 
    66 void TimerNatives::OnHandleDestroy(HandleType_t type, void *object)
    67 {
    68 	TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object);
    69 
    70 	g_Timers.KillTimer(pTimer->Timer);
    71 }
    72 
    73 TimerInfo *TimerNatives::CreateTimerInfo()
    74 {
    75 	TimerInfo *pInfo;
    76 
    77 	if (m_FreeTimers.empty())
    78 	{
    79 		pInfo = new TimerInfo;
    80 	} else {
    81 		pInfo = m_FreeTimers.front();
    82 		m_FreeTimers.pop();
    83 	}
    84 
    85 	return pInfo;
    86 }
    87 
    88 void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo)
    89 {
    90 	m_FreeTimers.push(pInfo);
    91 }
    92 
    93 ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData)
    94 {
    95 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
    96 	IPluginFunction *pFunc = pInfo->Hook;
    97 	cell_t res = static_cast<ResultType>(Pl_Continue);
    98 
    99 	pFunc->PushCell(pInfo->TimerHandle);
   100 	pFunc->PushCell(pInfo->UserData);
   101 	pFunc->Execute(&res);
   102 
   103 	return static_cast<ResultType>(res);
   104 }
   105 
   106 void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData)
   107 {
   108 	HandleSecurity sec;
   109 	HandleError herr;
   110 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
   111 	Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData);
   112 
   113 	sec.pOwner = pInfo->pContext->GetIdentity();
   114 	sec.pIdentity = g_pCoreIdent;
   115 
   116 	if (pInfo->Flags & TIMER_HNDL_CLOSE)
   117 	{
   118 		if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None)
   119 		{
   120 			g_Logger.LogError("Invalid data handle %x (error %d) passed during timer end", usrhndl, herr);
   121 		}
   122 	}
   123 
   124 	g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec);
   125 	DeleteTimerInfo(pInfo);
   126 }
   127 
   128 /*******************************
   129 *                              *
   130 * TIMER NATIVE IMPLEMENTATIONS *
   131 *                              *
   132 ********************************/
   133 
   134 static TimerNatives s_TimerNatives;
   135 
   136 static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params)
   137 {
   138 	IPluginFunction *pFunc;
   139 	TimerInfo *pInfo;
   140 	ITimer *pTimer;
   141 	Handle_t hndl;
   142 	int flags = params[4];
   143 
   144 	pFunc = pCtx->GetFunctionById(params[2]);
   145 	if (!pFunc)
   146 	{
   147 		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   148 	}
   149 
   150 	pInfo = s_TimerNatives.CreateTimerInfo();
   151 	pTimer = g_Timers.CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags);
   152 	hndl = g_HandleSys.CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   153 
   154 	pInfo->UserData = params[3];
   155 	pInfo->Flags = flags;
   156 	pInfo->TimerHandle = hndl;
   157 	pInfo->Hook = pFunc;
   158 	pInfo->Timer = pTimer;
   159 	pInfo->pContext = pCtx;
   160 
   161 	return hndl;
   162 }
   163 
   164 static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params)
   165 {
   166 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   167 	HandleError herr;
   168 	HandleSecurity sec;
   169 	TimerInfo *pInfo;
   170 
   171 	sec.pOwner = NULL;
   172 	sec.pIdentity = g_pCoreIdent;
   173 
   174 	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   175 		!= HandleError_None)
   176 	{
   177 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   178 	}
   179 
   180 	g_Timers.KillTimer(pInfo->Timer);
   181 
   182 	if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE))
   183 	{
   184 		sec.pOwner = pInfo->pContext->GetIdentity();
   185 		sec.pIdentity = g_pCoreIdent;
   186 
   187 		if ((herr=g_HandleSys.FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None)
   188 		{
   189 			return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr);
   190 		}
   191 	}
   192 
   193 	return 1;
   194 }
   195 
   196 static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params)
   197 {
   198 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   199 	HandleError herr;
   200 	HandleSecurity sec;
   201 	TimerInfo *pInfo;
   202 
   203 	sec.pOwner = NULL;
   204 	sec.pIdentity = g_pCoreIdent;
   205 
   206 	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   207 		!= HandleError_None)
   208 	{
   209 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   210 	}
   211 
   212 	g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false);
   213 
   214 	return 1;
   215 }
   216 
   217 REGISTER_NATIVES(timernatives)
   218 {
   219 	{"CreateTimer",				smn_CreateTimer},
   220 	{"KillTimer",				smn_KillTimer},
   221 	{"TriggerTimer",			smn_TriggerTimer},
   222 	{NULL,						NULL}
   223 };