faluco@612: /** ds@653: * vim: set ts=4 : ds@653: * =============================================================== ds@653: * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. ds@653: * =============================================================== ds@653: * ds@653: * This file is not open source and may not be copied without explicit ds@653: * written permission of AlliedModders LLC. This file may not be redistributed ds@653: * in whole or significant part. ds@653: * For information, see LICENSE.txt or http://www.sourcemod.net/license.php ds@653: * ds@653: * Version: $Id$ ds@653: */ faluco@612: faluco@612: #include "HandleSys.h" faluco@612: #include "TimerSys.h" faluco@612: #include "Logger.h" faluco@612: faluco@612: #define TIMER_HNDL_CLOSE (1<<9) faluco@612: faluco@612: HandleType_t g_TimerType; faluco@612: faluco@612: struct TimerInfo faluco@612: { faluco@612: ITimer *Timer; faluco@612: IPluginFunction *Hook; faluco@612: IPluginContext *pContext; faluco@612: Handle_t TimerHandle; faluco@612: int UserData; faluco@612: int Flags; faluco@612: }; faluco@612: faluco@612: class TimerNatives : faluco@612: public SMGlobalClass, faluco@612: public IHandleTypeDispatch, faluco@612: public ITimedEvent faluco@612: { faluco@641: public: faluco@641: ~TimerNatives(); faluco@612: public: //ITimedEvent faluco@612: ResultType OnTimer(ITimer *pTimer, void *pData); faluco@612: void OnTimerEnd(ITimer *pTimer, void *pData); faluco@612: public: //IHandleTypeDispatch faluco@612: void OnHandleDestroy(HandleType_t type, void *object); faluco@612: public: //SMGlobalClass faluco@612: void OnSourceModAllInitialized(); faluco@612: void OnSourceModShutdown(); faluco@612: public: faluco@612: TimerInfo *CreateTimerInfo(); faluco@612: void DeleteTimerInfo(TimerInfo *pInfo); faluco@612: private: faluco@612: CStack m_FreeTimers; faluco@612: }; faluco@612: faluco@641: TimerNatives::~TimerNatives() faluco@641: { faluco@641: CStack::iterator iter; faluco@641: for (iter=m_FreeTimers.begin(); iter!=m_FreeTimers.end(); iter++) faluco@641: { faluco@641: delete (*iter); faluco@641: } faluco@641: m_FreeTimers.popall(); faluco@641: } faluco@641: faluco@612: void TimerNatives::OnSourceModAllInitialized() faluco@612: { faluco@612: HandleAccess sec; faluco@612: sec.access[HandleAccess_Clone] |= HANDLE_RESTRICT_IDENTITY; faluco@612: faluco@612: g_TimerType = g_HandleSys.CreateType("Timer", this, 0, NULL, &sec, g_pCoreIdent, NULL); faluco@612: } faluco@612: faluco@612: void TimerNatives::OnSourceModShutdown() faluco@612: { faluco@612: g_HandleSys.RemoveType(g_TimerType, g_pCoreIdent); faluco@612: g_TimerType = 0; faluco@612: } faluco@612: faluco@612: void TimerNatives::OnHandleDestroy(HandleType_t type, void *object) faluco@612: { faluco@612: TimerInfo *pTimer = reinterpret_cast(object); faluco@612: faluco@612: g_Timers.KillTimer(pTimer->Timer); faluco@612: } faluco@612: faluco@612: TimerInfo *TimerNatives::CreateTimerInfo() faluco@612: { faluco@612: TimerInfo *pInfo; faluco@612: faluco@612: if (m_FreeTimers.empty()) faluco@612: { faluco@612: pInfo = new TimerInfo; faluco@612: } else { faluco@612: pInfo = m_FreeTimers.front(); faluco@612: m_FreeTimers.pop(); faluco@612: } faluco@612: faluco@612: return pInfo; faluco@612: } faluco@612: faluco@612: void TimerNatives::DeleteTimerInfo(TimerInfo *pInfo) faluco@612: { faluco@612: m_FreeTimers.push(pInfo); faluco@612: } faluco@612: faluco@612: ResultType TimerNatives::OnTimer(ITimer *pTimer, void *pData) faluco@612: { faluco@612: TimerInfo *pInfo = reinterpret_cast(pData); faluco@612: IPluginFunction *pFunc = pInfo->Hook; faluco@612: cell_t res = static_cast(Pl_Continue); faluco@612: faluco@612: pFunc->PushCell(pInfo->TimerHandle); faluco@612: pFunc->PushCell(pInfo->UserData); faluco@612: pFunc->Execute(&res); faluco@612: faluco@612: return static_cast(res); faluco@612: } faluco@612: faluco@612: void TimerNatives::OnTimerEnd(ITimer *pTimer, void *pData) faluco@612: { faluco@612: HandleSecurity sec; faluco@612: HandleError herr; faluco@612: TimerInfo *pInfo = reinterpret_cast(pData); faluco@612: Handle_t usrhndl = static_cast(pInfo->UserData); faluco@612: faluco@612: sec.pOwner = pInfo->pContext->GetIdentity(); faluco@612: sec.pIdentity = g_pCoreIdent; faluco@612: faluco@612: if (pInfo->Flags & TIMER_HNDL_CLOSE) faluco@612: { faluco@612: if ((herr=g_HandleSys.FreeHandle(usrhndl, &sec)) != HandleError_None) faluco@612: { faluco@612: g_Logger.LogError("Invalid data handle %x (error %d) passed during timer end", usrhndl, herr); faluco@612: } faluco@612: } faluco@612: faluco@612: g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec); faluco@613: DeleteTimerInfo(pInfo); faluco@612: } faluco@612: faluco@612: /******************************* faluco@612: * * faluco@612: * TIMER NATIVE IMPLEMENTATIONS * faluco@612: * * faluco@612: ********************************/ faluco@612: faluco@612: static TimerNatives s_TimerNatives; faluco@612: faluco@612: static cell_t smn_CreateTimer(IPluginContext *pCtx, const cell_t *params) faluco@612: { faluco@612: IPluginFunction *pFunc; faluco@612: TimerInfo *pInfo; faluco@612: ITimer *pTimer; faluco@612: Handle_t hndl; faluco@612: int flags = params[4]; faluco@612: faluco@612: pFunc = pCtx->GetFunctionById(params[2]); faluco@612: if (!pFunc) faluco@612: { faluco@612: return pCtx->ThrowNativeError("Invalid function id (%X)", params[2]); faluco@612: } faluco@612: faluco@612: pInfo = s_TimerNatives.CreateTimerInfo(); faluco@612: pTimer = g_Timers.CreateTimer(&s_TimerNatives, sp_ctof(params[1]), pInfo, flags); faluco@612: hndl = g_HandleSys.CreateHandle(g_TimerType, pInfo, pCtx->GetIdentity(), g_pCoreIdent, NULL); faluco@612: faluco@612: pInfo->UserData = params[3]; faluco@612: pInfo->Flags = flags; faluco@612: pInfo->TimerHandle = hndl; faluco@612: pInfo->Hook = pFunc; faluco@612: pInfo->Timer = pTimer; faluco@612: pInfo->pContext = pCtx; faluco@612: faluco@612: return hndl; faluco@612: } faluco@612: faluco@612: static cell_t smn_KillTimer(IPluginContext *pCtx, const cell_t *params) faluco@612: { faluco@612: Handle_t hndl = static_cast(params[1]); faluco@612: HandleError herr; faluco@612: HandleSecurity sec; faluco@612: TimerInfo *pInfo; faluco@612: dvander@1008: sec.pOwner = pCtx->GetIdentity(); faluco@612: sec.pIdentity = g_pCoreIdent; faluco@612: faluco@612: if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo)) faluco@612: != HandleError_None) faluco@612: { faluco@612: return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr); faluco@612: } faluco@612: faluco@612: g_Timers.KillTimer(pInfo->Timer); faluco@612: faluco@612: if (params[2] && !(pInfo->Flags & TIMER_HNDL_CLOSE)) faluco@612: { faluco@612: sec.pOwner = pInfo->pContext->GetIdentity(); faluco@612: sec.pIdentity = g_pCoreIdent; faluco@612: faluco@612: if ((herr=g_HandleSys.FreeHandle(static_cast(pInfo->UserData), &sec)) != HandleError_None) faluco@612: { faluco@612: return pCtx->ThrowNativeError("Invalid data handle %x (error %d)", hndl, herr); faluco@612: } faluco@612: } faluco@612: faluco@612: return 1; faluco@612: } faluco@612: faluco@612: static cell_t smn_TriggerTimer(IPluginContext *pCtx, const cell_t *params) faluco@612: { faluco@612: Handle_t hndl = static_cast(params[1]); faluco@612: HandleError herr; faluco@612: HandleSecurity sec; faluco@612: TimerInfo *pInfo; faluco@612: faluco@612: sec.pOwner = NULL; faluco@612: sec.pIdentity = g_pCoreIdent; faluco@612: faluco@612: if ((herr=g_HandleSys.ReadHandle(hndl, g_TimerType, &sec, (void **)&pInfo)) faluco@612: != HandleError_None) faluco@612: { faluco@612: return pCtx->ThrowNativeError("Invalid timer handle %x (error %d)", hndl, herr); faluco@612: } faluco@612: faluco@612: g_Timers.FireTimerOnce(pInfo->Timer, params[2] ? true : false); faluco@612: faluco@612: return 1; faluco@612: } faluco@612: dvander@822: static cell_t smn_GetTickedTime(IPluginContext *pContext, const cell_t *params) dvander@822: { dvander@822: cell_t *simulating; dvander@822: pContext->LocalToPhysAddr(params[1], &simulating); dvander@822: dvander@822: *simulating = g_SimTicks.ticking ? 0 : 1; dvander@822: dvander@822: float t = g_SimTicks.ticking ? gpGlobals->curtime : g_SimTicks.ticktime; dvander@822: return sp_ftoc(t); dvander@822: } dvander@822: faluco@612: REGISTER_NATIVES(timernatives) faluco@612: { faluco@612: {"CreateTimer", smn_CreateTimer}, faluco@612: {"KillTimer", smn_KillTimer}, faluco@612: {"TriggerTimer", smn_TriggerTimer}, dvander@822: {"GetTickedTime", smn_GetTickedTime}, faluco@612: {NULL, NULL} faluco@612: };