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