2 * ===============================================================
3 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
4 * ===============================================================
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
14 #include "HandleSys.h"
18 #define TIMER_HNDL_CLOSE (1<<9)
20 HandleType_t g_TimerType;
25 IPluginFunction *Hook;
26 IPluginContext *pContext;
34 public IHandleTypeDispatch,
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();
46 TimerInfo *CreateTimerInfo();
47 void DeleteTimerInfo(TimerInfo *pInfo);
49 CStack<TimerInfo *> m_FreeTimers;
52 void TimerNatives::OnSourceModAllInitialized()
55 sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
57 g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL);
60 void TimerNatives::OnSourceModShutdown()
62 g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent);
66 void TimerNatives::OnHandleDestroy(HandleType_t type, void *object)
68 TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object);
70 g_Timers.KillTimer(pTimer->Timer);
73 TimerInfo *TimerNatives::CreateTimerInfo()
77 if (m_FreeTimers.empty())
79 pInfo = new TimerInfo;
81 pInfo = m_FreeTimers.front();
88 void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo)
90 m_FreeTimers.push(pInfo);
93 ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData)
95 TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
96 IPluginFunction *pFunc = pInfo->Hook;
97 cell_t res = static_cast<ResultType>(Pl_Continue);
99 pFunc->PushCell(pInfo->TimerHandle);
100 pFunc->PushCell(pInfo->UserData);
101 pFunc->Execute(&res);
103 return static_cast<ResultType>(res);
106 void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData)
110 TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
111 Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData);
113 sec.pOwner = pInfo->pContext->GetIdentity();
114 sec.pIdentity = g_pCoreIdent;
116 if (pInfo->Flags & TIMER_HNDL_CLOSE)
118 if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None)
120 g_Logger.LogError("Invalid data handle %x (error %d) passed during timer end", usrhndl, herr);
124 g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec);
125 DeleteTimerInfo(pInfo);
128 /*******************************
130 * TIMER NATIVE IMPLEMENTATIONS *
132 ********************************/
134 static TimerNatives s_TimerNatives;
136 static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params)
138 IPluginFunction *pFunc;
142 int flags = params[4];
144 pFunc = pCtx->GetFunctionById(params[2]);
147 return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
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);
154 pInfo->UserData = params[3];
155 pInfo->Flags = flags;
156 pInfo->TimerHandle = hndl;
158 pInfo->Timer = pTimer;
159 pInfo->pContext = pCtx;
164 static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params)
166 Handle_t hndl = static_cast<Handle_t>(params[1]);
172 sec.pIdentity = g_pCoreIdent;
174 if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
177 return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
180 g_Timers.KillTimer(pInfo->Timer);
182 if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE))
184 sec.pOwner = pInfo->pContext->GetIdentity();
185 sec.pIdentity = g_pCoreIdent;
187 if ((herr=g_HandleSys.FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None)
189 return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr);
196 static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params)
198 Handle_t hndl = static_cast<Handle_t>(params[1]);
204 sec.pIdentity = g_pCoreIdent;
206 if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
209 return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
212 g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false);
217 REGISTER_NATIVES(timernatives)
219 {"CreateTimer", smn_CreateTimer},
220 {"KillTimer", smn_KillTimer},
221 {"TriggerTimer", smn_TriggerTimer},