3 * =============================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "HandleSys.h"
36 #define TIMER_HNDL_CLOSE (1<<9)
38 HandleType_t g_TimerType;
43 IPluginFunction *Hook;
44 IPluginContext *pContext;
52 public IHandleTypeDispatch,
58 ResultType OnTimer(ITimer *pTimer, void *pData);
59 void OnTimerEnd(ITimer *pTimer, void *pData);
60 public: //IHandleTypeDispatch
61 void OnHandleDestroy(HandleType_t type, void *object);
62 public: //SMGlobalClass
63 void OnSourceModAllInitialized();
64 void OnSourceModShutdown();
66 TimerInfo *CreateTimerInfo();
67 void DeleteTimerInfo(TimerInfo *pInfo);
69 CStack<TimerInfo *> m_FreeTimers;
72 TimerNatives::~TimerNatives()
74 CStack<TimerInfo *>::iterator iter;
75 for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
79 m_FreeTimers.popall();
82 void TimerNatives::OnSourceModAllInitialized()
85 sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
87 g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL);
90 void TimerNatives::OnSourceModShutdown()
92 g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent);
96 void TimerNatives::OnHandleDestroy(HandleType_t type, void *object)
98 TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object);
100 g_Timers.KillTimer(pTimer->Timer);
103 TimerInfo *TimerNatives::CreateTimerInfo()
107 if (m_FreeTimers.empty())
109 pInfo = new TimerInfo;
111 pInfo = m_FreeTimers.front();
118 void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo)
120 m_FreeTimers.push(pInfo);
123 ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData)
125 TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
126 IPluginFunction *pFunc = pInfo->Hook;
127 cell_t res = static_cast<ResultType>(Pl_Continue);
129 pFunc->PushCell(pInfo->TimerHandle);
130 pFunc->PushCell(pInfo->UserData);
131 pFunc->Execute(&res);
133 return static_cast<ResultType>(res);
136 void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData)
140 TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
141 Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData);
143 sec.pOwner = pInfo->pContext->GetIdentity();
144 sec.pIdentity = g_pCoreIdent;
146 if (pInfo->Flags & TIMER_HNDL_CLOSE)
148 if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None)
150 g_Logger.LogError("Invalid data handle %x (error %d) passed during timer end", usrhndl, herr);
154 g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec);
155 DeleteTimerInfo(pInfo);
158 /*******************************
160 * TIMER NATIVE IMPLEMENTATIONS *
162 ********************************/
164 static TimerNatives s_TimerNatives;
166 static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params)
168 IPluginFunction *pFunc;
172 int flags = params[4];
174 pFunc = pCtx->GetFunctionById(params[2]);
177 return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
180 pInfo = s_TimerNatives.CreateTimerInfo();
181 pTimer = g_Timers.CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags);
182 hndl = g_HandleSys.CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL);
184 pInfo->UserData = params[3];
185 pInfo->Flags = flags;
186 pInfo->TimerHandle = hndl;
188 pInfo->Timer = pTimer;
189 pInfo->pContext = pCtx;
194 static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params)
196 Handle_t hndl = static_cast<Handle_t>(params[1]);
201 sec.pOwner = pCtx->GetIdentity();
202 sec.pIdentity = g_pCoreIdent;
204 if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
207 return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
210 g_Timers.KillTimer(pInfo->Timer);
212 if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE))
214 sec.pOwner = pInfo->pContext->GetIdentity();
215 sec.pIdentity = g_pCoreIdent;
217 if ((herr=g_HandleSys.FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None)
219 return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr);
226 static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params)
228 Handle_t hndl = static_cast<Handle_t>(params[1]);
234 sec.pIdentity = g_pCoreIdent;
236 if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
239 return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
242 g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false);
247 static cell_t smn_GetTickedTime(IPluginContext *pContext, const cell_t *params)
250 pContext->LocalToPhysAddr(params[1], &simulating);
252 *simulating = g_SimTicks.ticking ? 0 : 1;
254 float t = g_SimTicks.ticking ? gpGlobals->curtime : g_SimTicks.ticktime;
258 REGISTER_NATIVES(timernatives)
260 {"CreateTimer", smn_CreateTimer},
261 {"KillTimer", smn_KillTimer},
262 {"TriggerTimer", smn_TriggerTimer},
263 {"GetTickedTime", smn_GetTickedTime},