faluco@612: /** ds@653: * vim: set ts=4 : ds@1330: * ============================================================================= dvander@1231: * SourceMod dvander@1231: * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. ds@1330: * ============================================================================= ds@653: * ds@1330: * This program is free software; you can redistribute it and/or modify it under ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the ds@1330: * Free Software Foundation. dvander@1231: * ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1330: * details. dvander@1231: * ds@1330: * You should have received a copy of the GNU General Public License along with ds@1330: * this program. If not, see . dvander@1231: * ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1330: * this exception to all derivative works. AlliedModders LLC defines further ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1330: * or . ds@653: * ds@653: * Version: $Id$ ds@653: */ faluco@612: faluco@612: #include "HandleSys.h" faluco@612: #include "TimerSys.h" faluco@1674: #include "PluginSys.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@1397: faluco@1397: g_HandleSys.InitAccessDefaults(NULL, &sec); faluco@1397: 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@1674: if ((herr=g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec)) != HandleError_None) faluco@1674: { faluco@1674: g_Logger.LogError("Invalid timer handle %x (error %d) on plugin %s during timer end", faluco@1674: pInfo->TimerHandle, faluco@1674: herr, faluco@1674: g_PluginSys.FindPluginByContext(pInfo->pContext->GetContext())->GetFilename()); faluco@1674: return; faluco@1674: } 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); dvander@1409: dvander@1409: if (!pTimer) dvander@1409: { dvander@1409: s_TimerNatives.DeleteTimerInfo(pInfo); dvander@1409: return 0; dvander@1409: } dvander@1409: 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@1397: 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.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@1412: return sp_ftoc(*g_pUniversalTime); dvander@822: } dvander@822: dvander@1415: static cell_t smn_GetMapTimeLeft(IPluginContext *pContext, const cell_t *params) dvander@1415: { dvander@1459: float time_left; dvander@1459: if (!g_Timers.GetMapTimeLeft(&time_left)) dvander@1415: { dvander@1462: return 0; dvander@1415: } dvander@1415: dvander@1462: cell_t *addr; dvander@1462: pContext->LocalToPhysAddr(params[1], &addr); dvander@1462: *addr = (int)time_left; dvander@1415: dvander@1462: return 1; dvander@1415: } dvander@1415: dvander@1415: static cell_t smn_GetMapTimeLimit(IPluginContext *pContext, const cell_t *params) dvander@1415: { dvander@1415: IMapTimer *pMapTimer = g_Timers.GetMapTimer(); dvander@1415: dvander@1415: if (!pMapTimer) dvander@1415: { dvander@1415: return 0; dvander@1415: } dvander@1415: dvander@1415: cell_t *addr; dvander@1415: pContext->LocalToPhysAddr(params[1], &addr); dvander@1415: dvander@1415: *addr = pMapTimer->GetMapTimeLimit(); dvander@1415: dvander@1415: return 1; dvander@1415: } dvander@1415: dvander@1415: static cell_t smn_ExtendMapTimeLimit(IPluginContext *pContext, const cell_t *params) dvander@1415: { dvander@1415: IMapTimer *pMapTimer = g_Timers.GetMapTimer(); dvander@1415: dvander@1415: if (!pMapTimer) dvander@1415: { dvander@1415: return 0; dvander@1415: } dvander@1415: dvander@1415: pMapTimer->ExtendMapTimeLimit(params[1]); dvander@1415: dvander@1415: return 1; dvander@1415: } dvander@1415: dvander@1461: static cell_t smn_IsServerProcessing(IPluginContext *pContext, const cell_t *params) dvander@1459: { dvander@1459: return (gpGlobals->frametime > 0.0f) ? 1 : 0; dvander@1459: } dvander@1459: 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}, dvander@1415: {"GetMapTimeLeft", smn_GetMapTimeLeft}, dvander@1415: {"GetMapTimeLimit", smn_GetMapTimeLimit}, dvander@1415: {"ExtendMapTimeLimit", smn_ExtendMapTimeLimit}, dvander@1461: {"IsServerProcessing", smn_IsServerProcessing}, faluco@612: {NULL, NULL} faluco@612: }; dvander@1462: