1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/smn_timers.cpp Sun Jul 06 04:49:55 2008 +0000
1.3 @@ -0,0 +1,346 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include "HandleSys.h"
1.36 +#include "TimerSys.h"
1.37 +#include "PluginSys.h"
1.38 +#include "Logger.h"
1.39 +#include "DebugReporter.h"
1.40 +
1.41 +#define TIMER_HNDL_CLOSE (1<<9)
1.42 +
1.43 +HandleType_t g_TimerType;
1.44 +
1.45 +struct TimerInfo
1.46 +{
1.47 + ITimer *Timer;
1.48 + IPluginFunction *Hook;
1.49 + IPluginContext *pContext;
1.50 + Handle_t TimerHandle;
1.51 + int UserData;
1.52 + int Flags;
1.53 +};
1.54 +
1.55 +class TimerNatives :
1.56 + public SMGlobalClass,
1.57 + public IHandleTypeDispatch,
1.58 + public ITimedEvent
1.59 +{
1.60 +public:
1.61 + ~TimerNatives();
1.62 +public: //ITimedEvent
1.63 + ResultType OnTimer(ITimer *pTimer, void *pData);
1.64 + void OnTimerEnd(ITimer *pTimer, void *pData);
1.65 +public: //IHandleTypeDispatch
1.66 + void OnHandleDestroy(HandleType_t type, void *object);
1.67 +public: //SMGlobalClass
1.68 + void OnSourceModAllInitialized();
1.69 + void OnSourceModShutdown();
1.70 +public:
1.71 + TimerInfo *CreateTimerInfo();
1.72 + void DeleteTimerInfo(TimerInfo *pInfo);
1.73 +private:
1.74 + CStack<TimerInfo *> m_FreeTimers;
1.75 +};
1.76 +
1.77 +TimerNatives::~TimerNatives()
1.78 +{
1.79 + CStack<TimerInfo *>::iterator iter;
1.80 + for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++)
1.81 + {
1.82 + delete (*iter);
1.83 + }
1.84 + m_FreeTimers.popall();
1.85 +}
1.86 +
1.87 +void TimerNatives::OnSourceModAllInitialized()
1.88 +{
1.89 + HandleAccess sec;
1.90 +
1.91 + g_HandleSys.InitAccessDefaults(NULL, &sec);
1.92 + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
1.93 +
1.94 + g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL);
1.95 +}
1.96 +
1.97 +void TimerNatives::OnSourceModShutdown()
1.98 +{
1.99 + g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent);
1.100 + g_TimerType = 0;
1.101 +}
1.102 +
1.103 +void TimerNatives::OnHandleDestroy(HandleType_t type, void *object)
1.104 +{
1.105 + TimerInfo *pTimer = reinterpret_cast<TimerInfo *>(object);
1.106 +
1.107 + g_Timers.KillTimer(pTimer->Timer);
1.108 +}
1.109 +
1.110 +TimerInfo *TimerNatives::CreateTimerInfo()
1.111 +{
1.112 + TimerInfo *pInfo;
1.113 +
1.114 + if (m_FreeTimers.empty())
1.115 + {
1.116 + pInfo = new TimerInfo;
1.117 + } else {
1.118 + pInfo = m_FreeTimers.front();
1.119 + m_FreeTimers.pop();
1.120 + }
1.121 +
1.122 + return pInfo;
1.123 +}
1.124 +
1.125 +void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo)
1.126 +{
1.127 + m_FreeTimers.push(pInfo);
1.128 +}
1.129 +
1.130 +ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData)
1.131 +{
1.132 + TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
1.133 + IPluginFunction *pFunc = pInfo->Hook;
1.134 + cell_t res = static_cast<ResultType>(Pl_Continue);
1.135 +
1.136 + pFunc->PushCell(pInfo->TimerHandle);
1.137 + pFunc->PushCell(pInfo->UserData);
1.138 + pFunc->Execute(&res);
1.139 +
1.140 + return static_cast<ResultType>(res);
1.141 +}
1.142 +
1.143 +void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData)
1.144 +{
1.145 + HandleSecurity sec;
1.146 + HandleError herr;
1.147 + TimerInfo *pInfo = reinterpret_cast<TimerInfo *>(pData);
1.148 + Handle_t usrhndl = static_cast<Handle_t>(pInfo->UserData);
1.149 +
1.150 + sec.pOwner = pInfo->pContext->GetIdentity();
1.151 + sec.pIdentity = g_pCoreIdent;
1.152 +
1.153 + if (pInfo->Flags & TIMER_HNDL_CLOSE)
1.154 + {
1.155 + if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None)
1.156 + {
1.157 + g_DbgReporter.GenerateError(pInfo->pContext,
1.158 + pInfo->Hook->GetFunctionID(),
1.159 + SP_ERROR_NATIVE,
1.160 + "Invalid data handle %x (error %d) passed during timer end",
1.161 + usrhndl,
1.162 + herr);
1.163 + }
1.164 + }
1.165 +
1.166 + if ((herr=g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec)) != HandleError_None)
1.167 + {
1.168 + g_DbgReporter.GenerateError(pInfo->pContext,
1.169 + pInfo->Hook->GetFunctionID(),
1.170 + SP_ERROR_NATIVE,
1.171 + "Invalid timer handle %x (error %d) during timer end, displayed function is timer callback, not the stack trace",
1.172 + pInfo->TimerHandle,
1.173 + herr);
1.174 + return;
1.175 + }
1.176 + DeleteTimerInfo(pInfo);
1.177 +}
1.178 +
1.179 +/*******************************
1.180 +* *
1.181 +* TIMER NATIVE IMPLEMENTATIONS *
1.182 +* *
1.183 +********************************/
1.184 +
1.185 +static TimerNatives s_TimerNatives;
1.186 +
1.187 +static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params)
1.188 +{
1.189 + IPluginFunction *pFunc;
1.190 + TimerInfo *pInfo;
1.191 + ITimer *pTimer;
1.192 + Handle_t hndl;
1.193 + int flags = params[4];
1.194 +
1.195 + pFunc = pCtx->GetFunctionById(params[2]);
1.196 + if (!pFunc)
1.197 + {
1.198 + return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]);
1.199 + }
1.200 +
1.201 + pInfo = s_TimerNatives.CreateTimerInfo();
1.202 + pTimer = g_Timers.CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags);
1.203 +
1.204 + if (!pTimer)
1.205 + {
1.206 + s_TimerNatives.DeleteTimerInfo(pInfo);
1.207 + return 0;
1.208 + }
1.209 +
1.210 + hndl = g_HandleSys.CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL);
1.211 +
1.212 + pInfo->UserData = params[3];
1.213 + pInfo->Flags = flags;
1.214 + pInfo->TimerHandle = hndl;
1.215 + pInfo->Hook = pFunc;
1.216 + pInfo->Timer = pTimer;
1.217 + pInfo->pContext = pCtx;
1.218 +
1.219 + return hndl;
1.220 +}
1.221 +
1.222 +static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params)
1.223 +{
1.224 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.225 + HandleError herr;
1.226 + HandleSecurity sec;
1.227 + TimerInfo *pInfo;
1.228 +
1.229 + sec.pOwner = pCtx->GetIdentity();
1.230 + sec.pIdentity = g_pCoreIdent;
1.231 +
1.232 + if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
1.233 + != HandleError_None)
1.234 + {
1.235 + return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
1.236 + }
1.237 +
1.238 + g_Timers.KillTimer(pInfo->Timer);
1.239 +
1.240 + if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE))
1.241 + {
1.242 + sec.pOwner = pInfo->pContext->GetIdentity();
1.243 + sec.pIdentity = g_pCoreIdent;
1.244 +
1.245 + if ((herr=g_HandleSys.FreeHandle(static_cast<Handle_t>(pInfo->UserData), &sec)) != HandleError_None)
1.246 + {
1.247 + return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr);
1.248 + }
1.249 + }
1.250 +
1.251 + return 1;
1.252 +}
1.253 +
1.254 +static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params)
1.255 +{
1.256 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.257 + HandleError herr;
1.258 + HandleSecurity sec;
1.259 + TimerInfo *pInfo;
1.260 +
1.261 + sec.pOwner = pCtx->GetIdentity();
1.262 + sec.pIdentity = g_pCoreIdent;
1.263 +
1.264 + if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo))
1.265 + != HandleError_None)
1.266 + {
1.267 + return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr);
1.268 + }
1.269 +
1.270 + g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false);
1.271 +
1.272 + return 1;
1.273 +}
1.274 +
1.275 +static cell_t smn_GetTickedTime(IPluginContext *pContext, const cell_t *params)
1.276 +{
1.277 + return sp_ftoc(*g_pUniversalTime);
1.278 +}
1.279 +
1.280 +static cell_t smn_GetMapTimeLeft(IPluginContext *pContext, const cell_t *params)
1.281 +{
1.282 + float time_left;
1.283 + if (!g_Timers.GetMapTimeLeft(&time_left))
1.284 + {
1.285 + return 0;
1.286 + }
1.287 +
1.288 + cell_t *addr;
1.289 + pContext->LocalToPhysAddr(params[1], &addr);
1.290 + *addr = (int)time_left;
1.291 +
1.292 + return 1;
1.293 +}
1.294 +
1.295 +static cell_t smn_GetMapTimeLimit(IPluginContext *pContext, const cell_t *params)
1.296 +{
1.297 + IMapTimer *pMapTimer = g_Timers.GetMapTimer();
1.298 +
1.299 + if (!pMapTimer)
1.300 + {
1.301 + return 0;
1.302 + }
1.303 +
1.304 + cell_t *addr;
1.305 + pContext->LocalToPhysAddr(params[1], &addr);
1.306 +
1.307 + *addr = pMapTimer->GetMapTimeLimit();
1.308 +
1.309 + return 1;
1.310 +}
1.311 +
1.312 +static cell_t smn_ExtendMapTimeLimit(IPluginContext *pContext, const cell_t *params)
1.313 +{
1.314 + IMapTimer *pMapTimer = g_Timers.GetMapTimer();
1.315 +
1.316 + if (!pMapTimer)
1.317 + {
1.318 + return 0;
1.319 + }
1.320 +
1.321 + pMapTimer->ExtendMapTimeLimit(params[1]);
1.322 +
1.323 + return 1;
1.324 +}
1.325 +
1.326 +static cell_t smn_IsServerProcessing(IPluginContext *pContext, const cell_t *params)
1.327 +{
1.328 + return (gpGlobals->frametime > 0.0f) ? 1 : 0;
1.329 +}
1.330 +
1.331 +static cell_t smn_GetTickInterval(IPluginContext *pContext, const cell_t *params)
1.332 +{
1.333 + return sp_ftoc(gpGlobals->interval_per_tick);
1.334 +}
1.335 +
1.336 +REGISTER_NATIVES(timernatives)
1.337 +{
1.338 + {"CreateTimer", smn_CreateTimer},
1.339 + {"KillTimer", smn_KillTimer},
1.340 + {"TriggerTimer", smn_TriggerTimer},
1.341 + {"GetTickedTime", smn_GetTickedTime},
1.342 + {"GetMapTimeLeft", smn_GetMapTimeLeft},
1.343 + {"GetMapTimeLimit", smn_GetMapTimeLimit},
1.344 + {"ExtendMapTimeLimit", smn_ExtendMapTimeLimit},
1.345 + {"IsServerProcessing", smn_IsServerProcessing},
1.346 + {"GetTickInterval", smn_GetTickInterval},
1.347 + {NULL, NULL}
1.348 +};
1.349 +