core/smn_timers.cpp
author Phong Dang <teame06@gmail.com>
Wed Aug 01 04:17:36 2007 +0000 (2007-08-01)
changeset 1235 88bb46f9731e
parent 1231 17badaf66ce4
child 1330 ab94316bb52b
permissions -rw-r--r--
Implemented requested amb603. Added voice natives.
     1 /**
     2  * vim: set ts=4 :
     3  * ================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * ================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or 
     9  * modify it under the terms of the GNU General Public License, 
    10  * version 3.0, as published by the Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to 
    21  * link the code of this program (as well as its derivative works) to 
    22  * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
    23  * Game MODs that run on software by the Valve Corporation.  You must 
    24  * obey the GNU General Public License in all respects for all other 
    25  * code used. Additionally, AlliedModders LLC grants this exception 
    26  * to all derivative works. AlliedModders LLC defines further 
    27  * exceptions, found in LICENSE.txt (as of this writing, version 
    28  * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
    29  *
    30  * Version: $Id$
    31  */
    32 
    33 #include "HandleSys.h"
    34 #include "TimerSys.h"
    35 #include "Logger.h"
    36 
    37 #define TIMER_HNDL_CLOSE	(1<<9)
    38 
    39 HandleType_t g_TimerType;
    40 
    41 struct TimerInfo 
    42 {
    43 	ITimer *Timer;
    44 	IPluginFunction *Hook;
    45 	IPluginContext *pContext;
    46 	Handle_t TimerHandle;
    47 	int UserData;
    48 	int Flags;
    49 };
    50 
    51 class TimerNatives :
    52 	public SMGlobalClass,
    53 	public IHandleTypeDispatch,
    54 	public ITimedEvent
    55 {
    56 public:
    57 	~TimerNatives();
    58 public: //ITimedEvent
    59 	ResultType OnTimer(ITimer *pTimer, void *pData);
    60 	void OnTimerEnd(ITimer *pTimer, void *pData);
    61 public: //IHandleTypeDispatch
    62 	void OnHandleDestroy(HandleType_t type, void *object);
    63 public: //SMGlobalClass
    64 	void OnSourceModAllInitialized();
    65 	void OnSourceModShutdown();
    66 public:
    67 	TimerInfo *CreateTimerInfo();
    68 	void DeleteTimerInfo(TimerInfo *pInfo);
    69 private:
    70 	CStack<TimerInfo *> m_FreeTimers;
    71 };
    72 
    73 TimerNatives::~TimerNatives()
    74 {
    75 	CStack<TimerInfo *>::iterator iter;
    76 	for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
    77 	{
    78 		delete (*iter);
    79 	}
    80 	m_FreeTimers.popall();
    81 }
    82 
    83 void TimerNatives::OnSourceModAllInitialized()
    84 {
    85 	HandleAccess sec;
    86 	sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY;
    87 
    88 	g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    89 }
    90 
    91 void TimerNatives::OnSourceModShutdown()
    92 {
    93 	g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent);
    94 	g_TimerType = 0;
    95 }
    96 
    97 void TimerNatives::OnHandleDestroy(HandleType_t type, void *object)
    98 {
    99 	TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object);
   100 
   101 	g_Timers.KillTimer(pTimer->Timer);
   102 }
   103 
   104 TimerInfo *TimerNatives::CreateTimerInfo()
   105 {
   106 	TimerInfo *pInfo;
   107 
   108 	if (m_FreeTimers.empty())
   109 	{
   110 		pInfo = new TimerInfo;
   111 	} else {
   112 		pInfo = m_FreeTimers.front();
   113 		m_FreeTimers.pop();
   114 	}
   115 
   116 	return pInfo;
   117 }
   118 
   119 void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo)
   120 {
   121 	m_FreeTimers.push(pInfo);
   122 }
   123 
   124 ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData)
   125 {
   126 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
   127 	IPluginFunction *pFunc = pInfo->Hook;
   128 	cell_t res = static_cast<ResultType>(Pl_Continue);
   129 
   130 	pFunc->PushCell(pInfo->TimerHandle);
   131 	pFunc->PushCell(pInfo->UserData);
   132 	pFunc->Execute(&res);
   133 
   134 	return static_cast<ResultType>(res);
   135 }
   136 
   137 void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData)
   138 {
   139 	HandleSecurity sec;
   140 	HandleError herr;
   141 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
   142 	Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData);
   143 
   144 	sec.pOwner = pInfo->pContext->GetIdentity();
   145 	sec.pIdentity = g_pCoreIdent;
   146 
   147 	if (pInfo->Flags & TIMER_HNDL_CLOSE)
   148 	{
   149 		if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None)
   150 		{
   151 			g_Logger.LogError("Invalid data handle %x (error %d) passed during timer end", usrhndl, herr);
   152 		}
   153 	}
   154 
   155 	g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec);
   156 	DeleteTimerInfo(pInfo);
   157 }
   158 
   159 /*******************************
   160 *                              *
   161 * TIMER NATIVE IMPLEMENTATIONS *
   162 *                              *
   163 ********************************/
   164 
   165 static TimerNatives s_TimerNatives;
   166 
   167 static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params)
   168 {
   169 	IPluginFunction *pFunc;
   170 	TimerInfo *pInfo;
   171 	ITimer *pTimer;
   172 	Handle_t hndl;
   173 	int flags = params[4];
   174 
   175 	pFunc = pCtx->GetFunctionById(params[2]);
   176 	if (!pFunc)
   177 	{
   178 		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   179 	}
   180 
   181 	pInfo = s_TimerNatives.CreateTimerInfo();
   182 	pTimer = g_Timers.CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags);
   183 	hndl = g_HandleSys.CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   184 
   185 	pInfo->UserData = params[3];
   186 	pInfo->Flags = flags;
   187 	pInfo->TimerHandle = hndl;
   188 	pInfo->Hook = pFunc;
   189 	pInfo->Timer = pTimer;
   190 	pInfo->pContext = pCtx;
   191 
   192 	return hndl;
   193 }
   194 
   195 static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params)
   196 {
   197 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   198 	HandleError herr;
   199 	HandleSecurity sec;
   200 	TimerInfo *pInfo;
   201 
   202 	sec.pOwner = pCtx->GetIdentity();
   203 	sec.pIdentity = g_pCoreIdent;
   204 
   205 	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   206 		!= HandleError_None)
   207 	{
   208 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   209 	}
   210 
   211 	g_Timers.KillTimer(pInfo->Timer);
   212 
   213 	if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE))
   214 	{
   215 		sec.pOwner = pInfo->pContext->GetIdentity();
   216 		sec.pIdentity = g_pCoreIdent;
   217 
   218 		if ((herr=g_HandleSys.FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None)
   219 		{
   220 			return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr);
   221 		}
   222 	}
   223 
   224 	return 1;
   225 }
   226 
   227 static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params)
   228 {
   229 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   230 	HandleError herr;
   231 	HandleSecurity sec;
   232 	TimerInfo *pInfo;
   233 
   234 	sec.pOwner = NULL;
   235 	sec.pIdentity = g_pCoreIdent;
   236 
   237 	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   238 		!= HandleError_None)
   239 	{
   240 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   241 	}
   242 
   243 	g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false);
   244 
   245 	return 1;
   246 }
   247 
   248 static cell_t smn_GetTickedTime(IPluginContext *pContext, const cell_t *params)
   249 {
   250 	cell_t *simulating;
   251 	pContext->LocalToPhysAddr(params[1], &simulating);
   252 
   253 	*simulating = g_SimTicks.ticking ? 0 : 1;
   254 
   255 	float t = g_SimTicks.ticking ? gpGlobals->curtime : g_SimTicks.ticktime;
   256 	return sp_ftoc(t);
   257 }
   258 
   259 REGISTER_NATIVES(timernatives)
   260 {
   261 	{"CreateTimer",				smn_CreateTimer},
   262 	{"KillTimer",				smn_KillTimer},
   263 	{"TriggerTimer",			smn_TriggerTimer},
   264 	{"GetTickedTime",			smn_GetTickedTime},
   265 	{NULL,						NULL}
   266 };