core/logic/smn_timers.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 3998 a40a92c903be
permissions -rw-r--r--
Update CS:GO team score gamedata.
     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 "common_logic.h"
    33 #include <string.h>
    34 #include <IHandleSys.h>
    35 #include <ITimerSystem.h>
    36 #include <IPluginSys.h>
    37 #include <sh_stack.h>
    38 #include "DebugReporter.h"
    39 
    40 using namespace SourceHook;
    41 
    42 #define TIMER_DATA_HNDL_CLOSE	(1<<9)
    43 #define TIMER_HNDL_CLOSE		(1<<9)
    44 
    45 HandleType_t g_TimerType;
    46 
    47 struct TimerInfo 
    48 {
    49 	ITimer *Timer;
    50 	IPluginFunction *Hook;
    51 	IPluginContext *pContext;
    52 	Handle_t TimerHandle;
    53 	int UserData;
    54 	int Flags;
    55 };
    56 
    57 class TimerNatives :
    58 	public SMGlobalClass,
    59 	public IHandleTypeDispatch,
    60 	public ITimedEvent
    61 {
    62 public:
    63 	~TimerNatives();
    64 public: //ITimedEvent
    65 	ResultType OnTimer(ITimer *pTimer, void *pData);
    66 	void OnTimerEnd(ITimer *pTimer, void *pData);
    67 public: //IHandleTypeDispatch
    68 	void OnHandleDestroy(HandleType_t type, void *object);
    69 public: //SMGlobalClass
    70 	void OnSourceModAllInitialized();
    71 	void OnSourceModShutdown();
    72 public:
    73 	TimerInfo *CreateTimerInfo();
    74 	void DeleteTimerInfo(TimerInfo *pInfo);
    75 private:
    76 	CStack<TimerInfo *> m_FreeTimers;
    77 };
    78 
    79 TimerNatives::~TimerNatives()
    80 {
    81 	CStack<TimerInfo *>::iterator iter;
    82 	for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
    83 	{
    84 		delete (*iter);
    85 	}
    86 	m_FreeTimers.popall();
    87 }
    88 
    89 void TimerNatives::OnSourceModAllInitialized()
    90 {
    91 	HandleAccess sec;
    92 
    93 	handlesys->InitAccessDefaults(NULL, &sec);
    94 	sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
    95 
    96 	g_TimerType = handlesys->CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    97 }
    98 
    99 void TimerNatives::OnSourceModShutdown()
   100 {
   101 	handlesys->RemoveType(g_TimerType, g_pCoreIdent);
   102 	g_TimerType = 0;
   103 }
   104 
   105 void TimerNatives::OnHandleDestroy(HandleType_t type, void *object)
   106 {
   107 	TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object);
   108 
   109 	timersys->KillTimer(pTimer->Timer);
   110 }
   111 
   112 TimerInfo *TimerNatives::CreateTimerInfo()
   113 {
   114 	TimerInfo *pInfo;
   115 
   116 	if (m_FreeTimers.empty())
   117 	{
   118 		pInfo = new TimerInfo;
   119 	} else {
   120 		pInfo = m_FreeTimers.front();
   121 		m_FreeTimers.pop();
   122 	}
   123 
   124 	return pInfo;
   125 }
   126 
   127 void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo)
   128 {
   129 	m_FreeTimers.push(pInfo);
   130 }
   131 
   132 ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData)
   133 {
   134 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
   135 	IPluginFunction *pFunc = pInfo->Hook;
   136 	cell_t res = static_cast<ResultType>(Pl_Continue);
   137 
   138 	pFunc->PushCell(pInfo->TimerHandle);
   139 	pFunc->PushCell(pInfo->UserData);
   140 	pFunc->Execute(&res);
   141 
   142 	return static_cast<ResultType>(res);
   143 }
   144 
   145 void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData)
   146 {
   147 	HandleSecurity sec;
   148 	HandleError herr;
   149 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
   150 	Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData);
   151 
   152 	sec.pOwner = pInfo->pContext->GetIdentity();
   153 	sec.pIdentity = g_pCoreIdent;
   154 
   155 	if (pInfo->Flags & TIMER_DATA_HNDL_CLOSE)
   156 	{
   157 		if ((herr=handlesys->FreeHandle(usrhndl, &sec)) != HandleError_None)
   158 		{
   159 			g_DbgReporter.GenerateError(pInfo->pContext, pInfo->Hook->GetFunctionID(), 
   160 							  	 SP_ERROR_NATIVE, 
   161 							  	 "Invalid data handle %x (error %d) passed during timer end with TIMER_DATA_HNDL_CLOSE",
   162 							  	 usrhndl, herr);
   163 		}
   164 	}
   165 
   166 	if (pInfo->TimerHandle != BAD_HANDLE)
   167 	{
   168 		if ((herr=handlesys->FreeHandle(pInfo->TimerHandle, &sec)) != HandleError_None)
   169 		{
   170 			g_DbgReporter.GenerateError(pInfo->pContext, pInfo->Hook->GetFunctionID(), 
   171 				SP_ERROR_NATIVE, 
   172 				"Invalid timer handle %x (error %d) during timer end, displayed function is timer callback, not the stack trace", 
   173 				pInfo->TimerHandle, herr);
   174 		}
   175 	}
   176 
   177 	DeleteTimerInfo(pInfo);
   178 }
   179 
   180 /*******************************
   181 *                              *
   182 * TIMER NATIVE IMPLEMENTATIONS *
   183 *                              *
   184 ********************************/
   185 
   186 static TimerNatives s_TimerNatives;
   187 
   188 static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params)
   189 {
   190 	IPluginFunction *pFunc;
   191 	TimerInfo *pInfo;
   192 	ITimer *pTimer;
   193 	Handle_t hndl;
   194 	int flags = params[4];
   195 
   196 	pFunc = pCtx->GetFunctionById(params[2]);
   197 	if (!pFunc)
   198 	{
   199 		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   200 	}
   201 
   202 	pInfo = s_TimerNatives.CreateTimerInfo();
   203 	pTimer = timersys->CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags);
   204 
   205 	if (!pTimer)
   206 	{
   207 		s_TimerNatives.DeleteTimerInfo(pInfo);
   208 		return 0;
   209 	}
   210 
   211 	pInfo->UserData = params[3];
   212 	pInfo->Flags = flags;
   213 	pInfo->Hook = pFunc;
   214 	pInfo->Timer = pTimer;
   215 	pInfo->pContext = pCtx;
   216 
   217 	hndl = handlesys->CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   218 
   219 	/* If we can't get a handle, the timer isn't refcounted against the plugin and 
   220 	 * we need to bail out to prevent a crash.
   221 	 */
   222 	if (hndl == BAD_HANDLE)
   223 	{
   224 		pInfo->TimerHandle = BAD_HANDLE;
   225 		timersys->KillTimer(pTimer);
   226 
   227 		return pCtx->ThrowNativeError("Could not create timer, no more handles");
   228 	}
   229 
   230 	pInfo->TimerHandle = hndl;
   231 
   232 	return hndl;
   233 }
   234 
   235 static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params)
   236 {
   237 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   238 	HandleError herr;
   239 	HandleSecurity sec;
   240 	TimerInfo *pInfo;
   241 
   242 	sec.pOwner = pCtx->GetIdentity();
   243 	sec.pIdentity = g_pCoreIdent;
   244 
   245 	if ((herr=handlesys->ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   246 		!= HandleError_None)
   247 	{
   248 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   249 	}
   250 
   251 	timersys->KillTimer(pInfo->Timer);
   252 
   253 	if (params[2] && !(pInfo->Flags & TIMER_DATA_HNDL_CLOSE))
   254 	{
   255 		sec.pOwner = pInfo->pContext->GetIdentity();
   256 		sec.pIdentity = g_pCoreIdent;
   257 
   258 		if ((herr=handlesys->FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None)
   259 		{
   260 			return pCtx->ThrowNativeError("Invalid data handle %x (error %d) on timer kill with TIMER_DATA_HNDL_CLOSE", hndl, herr);
   261 		}
   262 	}
   263 
   264 	return 1;
   265 }
   266 
   267 static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params)
   268 {
   269 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   270 	HandleError herr;
   271 	HandleSecurity sec;
   272 	TimerInfo *pInfo;
   273 
   274 	sec.pOwner = pCtx->GetIdentity();
   275 	sec.pIdentity = g_pCoreIdent;
   276 
   277 	if ((herr=handlesys->ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   278 		!= HandleError_None)
   279 	{
   280 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   281 	}
   282 
   283 	timersys->FireTimerOnce(pInfo->Timer, params[2] ? true : false);
   284 
   285 	return 1;
   286 }
   287 
   288 static cell_t smn_GetTickedTime(IPluginContext *pContext, const cell_t *params)
   289 {
   290 	return sp_ftoc(*serverGlobals.universalTime);
   291 }
   292 
   293 static cell_t smn_GetMapTimeLeft(IPluginContext *pContext, const cell_t *params)
   294 {
   295 	float time_left;
   296 	if (!timersys->GetMapTimeLeft(&time_left))
   297 	{
   298 		return 0;
   299 	}
   300 
   301 	cell_t *addr;
   302 	pContext->LocalToPhysAddr(params[1], &addr);
   303 	*addr = (int)time_left;
   304 
   305 	return 1;
   306 }
   307 
   308 static cell_t smn_GetMapTimeLimit(IPluginContext *pContext, const cell_t *params)
   309 {
   310 	IMapTimer *pMapTimer = timersys->GetMapTimer();
   311 
   312 	if (!pMapTimer)
   313 	{
   314 		return 0;
   315 	}
   316 
   317 	cell_t *addr;
   318 	pContext->LocalToPhysAddr(params[1], &addr);
   319 
   320 	*addr = pMapTimer->GetMapTimeLimit();
   321 
   322 	return 1;
   323 }
   324 
   325 static cell_t smn_ExtendMapTimeLimit(IPluginContext *pContext, const cell_t *params)
   326 {
   327 	IMapTimer *pMapTimer = timersys->GetMapTimer();
   328 
   329 	if (!pMapTimer)
   330 	{
   331 		return 0;
   332 	}
   333 
   334 	pMapTimer->ExtendMapTimeLimit(params[1]);
   335 
   336 	return 1;
   337 }
   338 
   339 static cell_t smn_IsServerProcessing(IPluginContext *pContext, const cell_t *params)
   340 {
   341 	return (*serverGlobals.frametime > 0.0f) ? 1 : 0;
   342 }
   343 
   344 static cell_t smn_GetTickInterval(IPluginContext *pContext, const cell_t *params)
   345 {
   346 	return sp_ftoc(*serverGlobals.interval_per_tick);
   347 }
   348 
   349 REGISTER_NATIVES(timernatives)
   350 {
   351 	{"CreateTimer",				smn_CreateTimer},
   352 	{"KillTimer",				smn_KillTimer},
   353 	{"TriggerTimer",			smn_TriggerTimer},
   354 	{"GetTickedTime",			smn_GetTickedTime},
   355 	{"GetMapTimeLeft",			smn_GetMapTimeLeft},
   356 	{"GetMapTimeLimit",			smn_GetMapTimeLimit},
   357 	{"ExtendMapTimeLimit",		smn_ExtendMapTimeLimit},
   358 	{"IsServerProcessing",		smn_IsServerProcessing},
   359 	{"GetTickInterval",			smn_GetTickInterval},
   360 	{NULL,						NULL}
   361 };
   362