3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
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
15 #include "HandleSys.h"
19 #define TIMER_HNDL_CLOSE (1<<9)
21 HandleType_t g_TimerType;
26 IPluginFunction *Hook;
27 IPluginContext *pContext;
35 public IHandleTypeDispatch,
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();
49 TimerInfo *CreateTimerInfo();
50 void DeleteTimerInfo(TimerInfo *pInfo);
52 CStack<TimerInfo *> m_FreeTimers;
55 TimerNatives::~TimerNatives()
57 CStack<TimerInfo *>::iterator iter;
58 for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
62 m_FreeTimers.popall();
65 void TimerNatives::OnSourceModAllInitialized()
68 sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
70 g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL);
73 void TimerNatives::OnSourceModShutdown()
75 g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent);
79 void TimerNatives::OnHandleDestroy(HandleType_t type, void *object)
81 TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object);
83 g_Timers.KillTimer(pTimer->Timer);
86 TimerInfo *TimerNatives::CreateTimerInfo()
90 if (m_FreeTimers.empty())
92 pInfo = new TimerInfo;
94 pInfo = m_FreeTimers.front();
101 void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo)
103 m_FreeTimers.push(pInfo);
106 ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData)
108 TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
109 IPluginFunction *pFunc = pInfo->Hook;
110 cell_t res = static_cast<ResultType>(Pl_Continue);
112 pFunc->PushCell(pInfo->TimerHandle);
113 pFunc->PushCell(pInfo->UserData);
114 pFunc->Execute(&res);
116 return static_cast<ResultType>(res);
119 void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData)
123 TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
124 Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData);
126 sec.pOwner = pInfo->pContext->GetIdentity();
127 sec.pIdentity = g_pCoreIdent;
129 if (pInfo->Flags & TIMER_HNDL_CLOSE)
131 if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None)
133 g_Logger.LogError("Invalid data handle %x (error %d) passed during timer end", usrhndl, herr);
137 g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec);
138 DeleteTimerInfo(pInfo);
141 /*******************************
143 * TIMER NATIVE IMPLEMENTATIONS *
145 ********************************/
147 static TimerNatives s_TimerNatives;
149 static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params)
151 IPluginFunction *pFunc;
155 int flags = params[4];
157 pFunc = pCtx->GetFunctionById(params[2]);
160 return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
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);
167 pInfo->UserData = params[3];
168 pInfo->Flags = flags;
169 pInfo->TimerHandle = hndl;
171 pInfo->Timer = pTimer;
172 pInfo->pContext = pCtx;
177 static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params)
179 Handle_t hndl = static_cast<Handle_t>(params[1]);
185 sec.pIdentity = g_pCoreIdent;
187 if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
190 return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
193 g_Timers.KillTimer(pInfo->Timer);
195 if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE))
197 sec.pOwner = pInfo->pContext->GetIdentity();
198 sec.pIdentity = g_pCoreIdent;
200 if ((herr=g_HandleSys.FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None)
202 return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr);
209 static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params)
211 Handle_t hndl = static_cast<Handle_t>(params[1]);
217 sec.pIdentity = g_pCoreIdent;
219 if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
222 return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
225 g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false);
230 REGISTER_NATIVES(timernatives)
232 {"CreateTimer", smn_CreateTimer},
233 {"KillTimer", smn_KillTimer},
234 {"TriggerTimer", smn_TriggerTimer},