core/smn_timers.cpp
author Borja Ferrer <faluco@alliedmods.net>
Sat Feb 23 11:40:45 2008 +0000 (2008-02-23)
changeset 1892 e1bc71f50865
parent 1674 cd474b45a045
child 1894 e6efc8ffa47a
permissions -rw-r--r--
improved timer error message (amb1474)
     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 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 
    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 
    87 	g_HandleSys.InitAccessDefaults(NULL, &sec);
    88 	sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
    89 
    90 	g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL);
    91 }
    92 
    93 void TimerNatives::OnSourceModShutdown()
    94 {
    95 	g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent);
    96 	g_TimerType = 0;
    97 }
    98 
    99 void TimerNatives::OnHandleDestroy(HandleType_t type, void *object)
   100 {
   101 	TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object);
   102 
   103 	g_Timers.KillTimer(pTimer->Timer);
   104 }
   105 
   106 TimerInfo *TimerNatives::CreateTimerInfo()
   107 {
   108 	TimerInfo *pInfo;
   109 
   110 	if (m_FreeTimers.empty())
   111 	{
   112 		pInfo = new TimerInfo;
   113 	} else {
   114 		pInfo = m_FreeTimers.front();
   115 		m_FreeTimers.pop();
   116 	}
   117 
   118 	return pInfo;
   119 }
   120 
   121 void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo)
   122 {
   123 	m_FreeTimers.push(pInfo);
   124 }
   125 
   126 ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData)
   127 {
   128 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
   129 	IPluginFunction *pFunc = pInfo->Hook;
   130 	cell_t res = static_cast<ResultType>(Pl_Continue);
   131 
   132 	pFunc->PushCell(pInfo->TimerHandle);
   133 	pFunc->PushCell(pInfo->UserData);
   134 	pFunc->Execute(&res);
   135 
   136 	return static_cast<ResultType>(res);
   137 }
   138 
   139 void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData)
   140 {
   141 	HandleSecurity sec;
   142 	HandleError herr;
   143 	TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
   144 	Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData);
   145 
   146 	sec.pOwner = pInfo->pContext->GetIdentity();
   147 	sec.pIdentity = g_pCoreIdent;
   148 
   149 	if (pInfo->Flags & TIMER_HNDL_CLOSE)
   150 	{
   151 		if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None)
   152 		{
   153 			g_Logger.LogError("Invalid data handle %x (error %d) passed during timer end on plugin %s", 
   154 								usrhndl, 
   155 								herr, 
   156 								g_PluginSys.FindPluginByContext(pInfo->pContext->GetContext())->GetFilename());
   157 		}
   158 	}
   159 
   160 	if ((herr=g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec)) != HandleError_None)
   161 	{
   162 		g_Logger.LogError("Invalid timer handle %x (error %d) on plugin %s during timer end", 
   163 							pInfo->TimerHandle, 
   164 							herr, 
   165 							g_PluginSys.FindPluginByContext(pInfo->pContext->GetContext())->GetFilename());
   166 		return;
   167 	}
   168 	DeleteTimerInfo(pInfo);
   169 }
   170 
   171 /*******************************
   172 *                              *
   173 * TIMER NATIVE IMPLEMENTATIONS *
   174 *                              *
   175 ********************************/
   176 
   177 static TimerNatives s_TimerNatives;
   178 
   179 static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params)
   180 {
   181 	IPluginFunction *pFunc;
   182 	TimerInfo *pInfo;
   183 	ITimer *pTimer;
   184 	Handle_t hndl;
   185 	int flags = params[4];
   186 
   187 	pFunc = pCtx->GetFunctionById(params[2]);
   188 	if (!pFunc)
   189 	{
   190 		return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
   191 	}
   192 
   193 	pInfo = s_TimerNatives.CreateTimerInfo();
   194 	pTimer = g_Timers.CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags);
   195 
   196 	if (!pTimer)
   197 	{
   198 		s_TimerNatives.DeleteTimerInfo(pInfo);
   199 		return 0;
   200 	}
   201 
   202 	hndl = g_HandleSys.CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   203 
   204 	pInfo->UserData = params[3];
   205 	pInfo->Flags = flags;
   206 	pInfo->TimerHandle = hndl;
   207 	pInfo->Hook = pFunc;
   208 	pInfo->Timer = pTimer;
   209 	pInfo->pContext = pCtx;
   210 
   211 	return hndl;
   212 }
   213 
   214 static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params)
   215 {
   216 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   217 	HandleError herr;
   218 	HandleSecurity sec;
   219 	TimerInfo *pInfo;
   220 
   221 	sec.pOwner = pCtx->GetIdentity();
   222 	sec.pIdentity = g_pCoreIdent;
   223 
   224 	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   225 		!= HandleError_None)
   226 	{
   227 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   228 	}
   229 
   230 	g_Timers.KillTimer(pInfo->Timer);
   231 
   232 	if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE))
   233 	{
   234 		sec.pOwner = pInfo->pContext->GetIdentity();
   235 		sec.pIdentity = g_pCoreIdent;
   236 
   237 		if ((herr=g_HandleSys.FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None)
   238 		{
   239 			return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr);
   240 		}
   241 	}
   242 
   243 	return 1;
   244 }
   245 
   246 static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params)
   247 {
   248 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   249 	HandleError herr;
   250 	HandleSecurity sec;
   251 	TimerInfo *pInfo;
   252 
   253 	sec.pOwner = pCtx->GetIdentity();
   254 	sec.pIdentity = g_pCoreIdent;
   255 
   256 	if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
   257 		!= HandleError_None)
   258 	{
   259 		return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
   260 	}
   261 
   262 	g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false);
   263 
   264 	return 1;
   265 }
   266 
   267 static cell_t smn_GetTickedTime(IPluginContext *pContext, const cell_t *params)
   268 {
   269 	return sp_ftoc(*g_pUniversalTime);
   270 }
   271 
   272 static cell_t smn_GetMapTimeLeft(IPluginContext *pContext, const cell_t *params)
   273 {
   274 	float time_left;
   275 	if (!g_Timers.GetMapTimeLeft(&time_left))
   276 	{
   277 		return 0;
   278 	}
   279 
   280 	cell_t *addr;
   281 	pContext->LocalToPhysAddr(params[1], &addr);
   282 	*addr = (int)time_left;
   283 
   284 	return 1;
   285 }
   286 
   287 static cell_t smn_GetMapTimeLimit(IPluginContext *pContext, const cell_t *params)
   288 {
   289 	IMapTimer *pMapTimer = g_Timers.GetMapTimer();
   290 
   291 	if (!pMapTimer)
   292 	{
   293 		return 0;
   294 	}
   295 
   296 	cell_t *addr;
   297 	pContext->LocalToPhysAddr(params[1], &addr);
   298 
   299 	*addr = pMapTimer->GetMapTimeLimit();
   300 
   301 	return 1;
   302 }
   303 
   304 static cell_t smn_ExtendMapTimeLimit(IPluginContext *pContext, const cell_t *params)
   305 {
   306 	IMapTimer *pMapTimer = g_Timers.GetMapTimer();
   307 
   308 	if (!pMapTimer)
   309 	{
   310 		return 0;
   311 	}
   312 
   313 	pMapTimer->ExtendMapTimeLimit(params[1]);
   314 
   315 	return 1;
   316 }
   317 
   318 static cell_t smn_IsServerProcessing(IPluginContext *pContext, const cell_t *params)
   319 {
   320 	return (gpGlobals->frametime > 0.0f) ? 1 : 0;
   321 }
   322 
   323 REGISTER_NATIVES(timernatives)
   324 {
   325 	{"CreateTimer",				smn_CreateTimer},
   326 	{"KillTimer",				smn_KillTimer},
   327 	{"TriggerTimer",			smn_TriggerTimer},
   328 	{"GetTickedTime",			smn_GetTickedTime},
   329 	{"GetMapTimeLeft",			smn_GetMapTimeLeft},
   330 	{"GetMapTimeLimit",			smn_GetMapTimeLimit},
   331 	{"ExtendMapTimeLimit",		smn_ExtendMapTimeLimit},
   332 	{"IsServerProcessing",		smn_IsServerProcessing},
   333 	{NULL,						NULL}
   334 };
   335