core/smn_timers.cpp
author Borja Ferrer <faluco@alliedmods.net>
Fri Jul 04 19:04:33 2008 +0000 (2008-07-04)
changeset 2155 3f1fd7ab3d86
parent 2063 4b5761e0e3a3
child 2289 44045ead61cd
permissions -rw-r--r--
fixed amb1801, IsFakeClient() wasn't working for TF2 causing false results and crashes
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     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.
    11  * 
    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
    15  * details.
    16  *
    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/>.
    19  *
    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>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "HandleSys.h"
    33 #include "TimerSys.h"
    34 #include "PluginSys.h"
    35 #include "Logger.h"
    36 #include "DebugReporter.h"
    37 
    38 #define TIMER_HNDL_CLOSE	(1<<9)
    39 
    40 HandleType_t g_TimerType;
    41 
    42 struct TimerInfo 
    43 {
    44 	ITimer *Timer;
    45 	IPluginFunction *Hook;
    46 	IPluginContext *pContext;
    47 	Handle_t TimerHandle;
    48 	int UserData;
    49 	int Flags;
    50 };
    51 
    52 class TimerNatives :
    53 	public SMGlobalClass,
    54 	public IHandleTypeDispatch,
    55 	public ITimedEvent
    56 {
    57 public:
    58 	~TimerNatives();
    59 public: //ITimedEvent
    60 	ResultType OnTimer(ITimer *pTimer, void *pData);
    61 	void OnTimerEnd(ITimer *pTimer, void *pData);
    62 public: //IHandleTypeDispatch
    63 	void OnHandleDestroy(HandleType_t type, void *object);
    64 public: //SMGlobalClass
    65 	void OnSourceModAllInitialized();
    66 	void OnSourceModShutdown();
    67 public:
    68 	TimerInfo *CreateTimerInfo();
    69 	void DeleteTimerInfo(TimerInfo *pInfo);
    70 private:
    71 	CStack<TimerInfo *> m_FreeTimers;
    72 };
    73 
    74 TimerNatives::~TimerNatives()
    75 {
    76 	CStack<TimerInfo *>::iterator iter;
    77 	for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
    78 	{
    79 		delete (*iter);
    80 	}
    81 	m_FreeTimers.popall();
    82 }
    83 
    84 void TimerNatives::OnSourceModAllInitialized()
    85 {
    86 	HandleAccess sec;
    87 
    88 	g_HandleSys.InitAccessDefaults(NULL, &sec);
    89 	sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
    90 
    91 	g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    92 }
    93 
    94 void TimerNatives::OnSourceModShutdown()
    95 {
    96 	g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent);
    97 	g_TimerType = 0;
    98 }
    99 
   100 void TimerNatives::OnHandleDestroy(HandleType_t type, void *object)
   101 {
   102 	TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object);
   103 
   104 	g_Timers.KillTimer(pTimer->Timer);
   105 }
   106 
   107 TimerInfo *TimerNatives::CreateTimerInfo()
   108 {
   109 	TimerInfo *pInfo;
   110 
   111 	if (m_FreeTimers.empty())
   112 	{
   113 		pInfo = new TimerInfo;
   114 	} else {
   115 		pInfo = m_FreeTimers.front();
   116 		m_FreeTimers.pop();
   117 	}
   118 
   119 	return pInfo;
   120 }
   121 
   122 void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo)
   123 {
   124 	m_FreeTimers.push(pInfo);
   125 }
   126 
   127 ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData)
   128 {
   129 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
   130 	IPluginFunction *pFunc = pInfo->Hook;
   131 	cell_t res = static_cast<ResultType>(Pl_Continue);
   132 
   133 	pFunc->PushCell(pInfo->TimerHandle);
   134 	pFunc->PushCell(pInfo->UserData);
   135 	pFunc->Execute(&res);
   136 
   137 	return static_cast<ResultType>(res);
   138 }
   139 
   140 void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData)
   141 {
   142 	HandleSecurity sec;
   143 	HandleError herr;
   144 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
   145 	Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData);
   146 
   147 	sec.pOwner = pInfo->pContext->GetIdentity();
   148 	sec.pIdentity = g_pCoreIdent;
   149 
   150 	if (pInfo->Flags & TIMER_HNDL_CLOSE)
   151 	{
   152 		if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None)
   153 		{
   154 			g_DbgReporter.GenerateError(pInfo->pContext,
   155 										pInfo->Hook->GetFunctionID(), 
   156 										SP_ERROR_NATIVE, 
   157 										"Invalid data handle %x (error %d) passed during timer end",
   158 										usrhndl, 
   159 										herr);
   160 		}
   161 	}
   162 
   163 	if ((herr=g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec)) != HandleError_None)
   164 	{
   165 		g_DbgReporter.GenerateError(pInfo->pContext, 
   166 									pInfo->Hook->GetFunctionID(), 
   167 									SP_ERROR_NATIVE, 
   168 									"Invalid timer handle %x (error %d) during timer end, displayed function is timer callback, not the stack trace", 
   169 									pInfo->TimerHandle, 
   170 									herr);
   171 		return;
   172 	}
   173 	DeleteTimerInfo(pInfo);
   174 }
   175 
   176 /*******************************
   177 *                              *
   178 * TIMER NATIVE IMPLEMENTATIONS *
   179 *                              *
   180 ********************************/
   181 
   182 static TimerNatives s_TimerNatives;
   183 
   184 static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params)
   185 {
   186 	IPluginFunction *pFunc;
   187 	TimerInfo *pInfo;
   188 	ITimer *pTimer;
   189 	Handle_t hndl;
   190 	int flags = params[4];
   191 
   192 	pFunc = pCtx->GetFunctionById(params[2]);
   193 	if (!pFunc)
   194 	{
   195 		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   196 	}
   197 
   198 	pInfo = s_TimerNatives.CreateTimerInfo();
   199 	pTimer = g_Timers.CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags);
   200 
   201 	if (!pTimer)
   202 	{
   203 		s_TimerNatives.DeleteTimerInfo(pInfo);
   204 		return 0;
   205 	}
   206 
   207 	hndl = g_HandleSys.CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   208 
   209 	pInfo->UserData = params[3];
   210 	pInfo->Flags = flags;
   211 	pInfo->TimerHandle = hndl;
   212 	pInfo->Hook = pFunc;
   213 	pInfo->Timer = pTimer;
   214 	pInfo->pContext = pCtx;
   215 
   216 	return hndl;
   217 }
   218 
   219 static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params)
   220 {
   221 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   222 	HandleError herr;
   223 	HandleSecurity sec;
   224 	TimerInfo *pInfo;
   225 
   226 	sec.pOwner = pCtx->GetIdentity();
   227 	sec.pIdentity = g_pCoreIdent;
   228 
   229 	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   230 		!= HandleError_None)
   231 	{
   232 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   233 	}
   234 
   235 	g_Timers.KillTimer(pInfo->Timer);
   236 
   237 	if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE))
   238 	{
   239 		sec.pOwner = pInfo->pContext->GetIdentity();
   240 		sec.pIdentity = g_pCoreIdent;
   241 
   242 		if ((herr=g_HandleSys.FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None)
   243 		{
   244 			return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr);
   245 		}
   246 	}
   247 
   248 	return 1;
   249 }
   250 
   251 static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params)
   252 {
   253 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   254 	HandleError herr;
   255 	HandleSecurity sec;
   256 	TimerInfo *pInfo;
   257 
   258 	sec.pOwner = pCtx->GetIdentity();
   259 	sec.pIdentity = g_pCoreIdent;
   260 
   261 	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   262 		!= HandleError_None)
   263 	{
   264 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   265 	}
   266 
   267 	g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false);
   268 
   269 	return 1;
   270 }
   271 
   272 static cell_t smn_GetTickedTime(IPluginContext *pContext, const cell_t *params)
   273 {
   274 	return sp_ftoc(*g_pUniversalTime);
   275 }
   276 
   277 static cell_t smn_GetMapTimeLeft(IPluginContext *pContext, const cell_t *params)
   278 {
   279 	float time_left;
   280 	if (!g_Timers.GetMapTimeLeft(&time_left))
   281 	{
   282 		return 0;
   283 	}
   284 
   285 	cell_t *addr;
   286 	pContext->LocalToPhysAddr(params[1], &addr);
   287 	*addr = (int)time_left;
   288 
   289 	return 1;
   290 }
   291 
   292 static cell_t smn_GetMapTimeLimit(IPluginContext *pContext, const cell_t *params)
   293 {
   294 	IMapTimer *pMapTimer = g_Timers.GetMapTimer();
   295 
   296 	if (!pMapTimer)
   297 	{
   298 		return 0;
   299 	}
   300 
   301 	cell_t *addr;
   302 	pContext->LocalToPhysAddr(params[1], &addr);
   303 
   304 	*addr = pMapTimer->GetMapTimeLimit();
   305 
   306 	return 1;
   307 }
   308 
   309 static cell_t smn_ExtendMapTimeLimit(IPluginContext *pContext, const cell_t *params)
   310 {
   311 	IMapTimer *pMapTimer = g_Timers.GetMapTimer();
   312 
   313 	if (!pMapTimer)
   314 	{
   315 		return 0;
   316 	}
   317 
   318 	pMapTimer->ExtendMapTimeLimit(params[1]);
   319 
   320 	return 1;
   321 }
   322 
   323 static cell_t smn_IsServerProcessing(IPluginContext *pContext, const cell_t *params)
   324 {
   325 	return (gpGlobals->frametime > 0.0f) ? 1 : 0;
   326 }
   327 
   328 static cell_t smn_GetTickInterval(IPluginContext *pContext, const cell_t *params)
   329 {
   330 	return sp_ftoc(gpGlobals->interval_per_tick);
   331 }
   332 
   333 REGISTER_NATIVES(timernatives)
   334 {
   335 	{"CreateTimer",				smn_CreateTimer},
   336 	{"KillTimer",				smn_KillTimer},
   337 	{"TriggerTimer",			smn_TriggerTimer},
   338 	{"GetTickedTime",			smn_GetTickedTime},
   339 	{"GetMapTimeLeft",			smn_GetMapTimeLeft},
   340 	{"GetMapTimeLimit",			smn_GetMapTimeLimit},
   341 	{"ExtendMapTimeLimit",		smn_ExtendMapTimeLimit},
   342 	{"IsServerProcessing",		smn_IsServerProcessing},
   343 	{"GetTickInterval",			smn_GetTickInterval},
   344 	{NULL,						NULL}
   345 };
   346