diff --git a/core/CConVarManager.cpp b/core/CConVarManager.cpp index 734379a0..5c6e6f02 100644 --- a/core/CConVarManager.cpp +++ b/core/CConVarManager.cpp @@ -88,7 +88,7 @@ void CConVarManager::OnPluginDestroyed(IPlugin *plugin) CVector *cvarList; // If plugin has a convar list, free its memory - if (plugin->GetProperty("ConVar", reinterpret_cast(&cvarList), true)) + if (plugin->GetProperty("ConVarList", reinterpret_cast(&cvarList), true)) { delete cvarList; } @@ -97,21 +97,21 @@ void CConVarManager::OnPluginDestroyed(IPlugin *plugin) void CConVarManager::OnHandleDestroy(HandleType_t type, void *object) { ConVarInfo *info; - ConVar *cvar = static_cast(object); + ConVar *pConVar = static_cast(object); // Find convar in lookup trie - sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info)); + sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast(&info)); // If convar was created by SourceMod plugin... if (info->sourceMod) { // Delete string allocations - delete [] cvar->GetName(); - delete [] cvar->GetDefault(); - delete [] cvar->GetHelpText(); + delete [] pConVar->GetName(); + delete [] pConVar->GetDefault(); + delete [] pConVar->GetHelpText(); - // Then unregister it - g_SMAPI->UnregisterConCmdBase(g_PLAPI, cvar); + // Then unlink it from SourceMM + g_SMAPI->UnregisterConCmdBase(g_PLAPI, pConVar); } } @@ -151,8 +151,8 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc // Iterate convar list and display each one for (size_t i = 0; i < cvarList->size(); i++, id++) { - ConVar *cvar = (*cvarList)[i]; - g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, cvar->GetName(), cvar->GetString()); + ConVar *pConVar = (*cvarList)[i]; + g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, pConVar->GetName(), pConVar->GetString()); } return; @@ -164,16 +164,16 @@ void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argc Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max) { - ConVar *cvar = NULL; + ConVar *pConVar = NULL; ConVarInfo *info = NULL; CVector *cvarList = NULL; Handle_t hndl = 0; // Find out if the convar exists already - cvar = icvar->FindVar(name); + pConVar = icvar->FindVar(name); // If the convar already exists... - if (cvar != NULL) + if (pConVar != NULL) { // First check if we already have a handle to it if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast(&info))) @@ -182,13 +182,13 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name return info->handle; } else { // If we don't, then create a new handle from the convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); info = new ConVarInfo; info->handle = hndl; info->sourceMod = false; info->changeForward = NULL; - info->origCallback = cvar->GetCallback(); + info->origCallback = pConVar->GetCallback(); m_ConVars.push_back(info); @@ -210,27 +210,27 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name } // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it! - cvar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(helpText), hasMin, min, hasMax, max); + pConVar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(helpText), hasMin, min, hasMax, max); // Find plugin creating convar IPlugin *pl = g_PluginSys.FindPluginByContext(pContext->GetContext()); // Get convar list from 'ConVar' property of plugin - pl->GetProperty("ConVar", reinterpret_cast(&cvarList)); + pl->GetProperty("ConVarList", reinterpret_cast(&cvarList)); // If 'ConVar' property doesn't exist... if (cvarList == NULL) { // Then create it cvarList = new CVector; - pl->SetProperty("ConVar", cvarList); + pl->SetProperty("ConVarList", cvarList); } // Add new convar to plugin's list - cvarList->push_back(cvar); + cvarList->push_back(pConVar); // Create a handle from the new convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); info = new ConVarInfo; info->handle = hndl; @@ -248,15 +248,15 @@ Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name Handle_t CConVarManager::FindConVar(const char *name) { - ConVar *cvar = NULL; + ConVar *pConVar = NULL; ConVarInfo *info = NULL; Handle_t hndl = 0; // Search for convar - cvar = icvar->FindVar(name); + pConVar = icvar->FindVar(name); // If it doesn't exist, then return an invalid handle - if (cvar == NULL) + if (pConVar == NULL) { return BAD_HANDLE; } @@ -269,13 +269,13 @@ Handle_t CConVarManager::FindConVar(const char *name) } // If we don't, then create a new handle from the convar - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL); + hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL); info = new ConVarInfo; info->handle = hndl; info->sourceMod = false; info->changeForward = NULL; - info->origCallback = cvar->GetCallback(); + info->origCallback = pConVar->GetCallback(); m_ConVars.push_back(info); @@ -285,7 +285,7 @@ Handle_t CConVarManager::FindConVar(const char *name) return hndl; } -void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) +void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid) { IPluginFunction *func = pContext->GetFunctionById(funcid); IChangeableForward *fwd = NULL; @@ -300,7 +300,7 @@ void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, fu } // Create a forward name - UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", cvar->GetName()); + UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", pConVar->GetName()); // First find out if the forward already exists g_Forwards.FindForward(fwdName, &fwd); @@ -315,13 +315,13 @@ void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, fu fwd = g_Forwards.CreateForwardEx(fwdName, ET_Ignore, 3, p); // Find the convar in the lookup trie - if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) + if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast(&info))) { // Set the convar's forward to the newly created one info->changeForward = fwd; // Set the convar's callback to our static one - cvar->InstallChangeCallback(OnConVarChanged); + pConVar->InstallChangeCallback(OnConVarChanged); } } @@ -329,7 +329,7 @@ void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, fu fwd->AddFunction(func); } -void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid) +void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid) { IPluginFunction *func = pContext->GetFunctionById(funcid); IChangeableForward *fwd = NULL; @@ -343,7 +343,7 @@ void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, } // Find the convar in the lookup trie - if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast(&info))) + if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast(&info))) { // Get the forward fwd = info->changeForward; @@ -351,14 +351,14 @@ void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, // If the forward doesn't exist, we can't unhook anything if (fwd == NULL) { - pContext->ThrowNativeError("Convar \"%s\" has no active hook", cvar->GetName()); + pContext->ThrowNativeError("Convar \"%s\" has no active hook", pConVar->GetName()); return; } // Remove the function from the forward's list if (!fwd->RemoveFunction(func)) { - pContext->ThrowNativeError("Invalid hook callback specified for convar \"%s\"", cvar->GetName()); + pContext->ThrowNativeError("Invalid hook callback specified for convar \"%s\"", pConVar->GetName()); return; } @@ -370,15 +370,15 @@ void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, info->changeForward = NULL; // Put the back the original convar callback - cvar->InstallChangeCallback(info->origCallback); + pConVar->InstallChangeCallback(info->origCallback); } } } -void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) +void CConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) { // If the values are the same... - if (strcmp(cvar->GetString(), oldValue) == 0) + if (strcmp(pConVar->GetString(), oldValue) == 0) { // Exit early in order to not trigger callbacks return; @@ -388,7 +388,7 @@ void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) ConVarInfo *info; // Find the convar in the lookup trie - sm_trie_retrieve(cache, cvar->GetName(), reinterpret_cast(&info)); + sm_trie_retrieve(cache, pConVar->GetName(), reinterpret_cast(&info)); FnChangeCallback origCallback = info->origCallback; IChangeableForward *fwd = info->changeForward; @@ -396,12 +396,12 @@ void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue) // If there was a change callback installed previously, call it if (origCallback) { - origCallback(cvar, oldValue); + origCallback(pConVar, oldValue); } // Now call forwards in plugins that have hooked this fwd->PushCell(info->handle); - fwd->PushString(cvar->GetString()); + fwd->PushString(pConVar->GetString()); fwd->PushString(oldValue); fwd->Execute(NULL); } diff --git a/core/CConVarManager.h b/core/CConVarManager.h index 80a05dda..aeecbf74 100644 --- a/core/CConVarManager.h +++ b/core/CConVarManager.h @@ -85,17 +85,17 @@ public: /** * Add a function to call when the specified convar changes. */ - void HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid); + void HookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid); /** * Remove a function from the forward that will be called when the specified convar changes. */ - void UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid); + void UnhookConVarChange(IPluginContext *pContext, ConVar *pConVar, funcid_t funcid); private: /** - * Static callback that Valve's ConVar class executes when the convar's value changes. - */ - static void OnConVarChanged(ConVar *cvar, const char *oldValue); + * Static callback that Valve's ConVar class executes when the convar's value changes. + */ + static void OnConVarChanged(ConVar *pConVar, const char *oldValue); private: HandleType_t m_ConVarType; List m_ConVars; diff --git a/core/EventManager.cpp b/core/EventManager.cpp new file mode 100644 index 00000000..bf70b97f --- /dev/null +++ b/core/EventManager.cpp @@ -0,0 +1,363 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "EventManager.h" +#include "ForwardSys.h" +#include "HandleSys.h" +#include "PluginSys.h" +#include "sm_stringutil.h" + +EventManager g_EventManager; + +SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool); + +typedef List EventHookList; + +const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell}; + +EventManager::EventManager() : m_EventCopy(NULL), m_NotifyState(true) +{ + /* Create an event lookup trie */ + m_EventHooks = sm_trie_create(); +} + +EventManager::~EventManager() +{ + sm_trie_destroy(m_EventHooks); +} + +void EventManager::OnSourceModAllInitialized() +{ + /* Add a hook for IGameEventManager2::FireEvent() */ + SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false); + SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true); + + HandleAccess sec; + + /* Handle access security for 'GameEvent' handle type */ + sec.access[HandleAccess_Read] = 0; + sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + + /* Create the 'GameEvent' handle type */ + m_EventType = g_HandleSys.CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL); +} + +void EventManager::OnSourceModShutdown() +{ + /* Remove hook for IGameEventManager2::FireEvent() */ + SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false); + SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true); + + /* Remove the 'GameEvent' handle type */ + g_HandleSys.RemoveType(m_EventType, g_pCoreIdent); + + /* Remove ourselves as listener for events */ + gameevents->RemoveListener(this); +} + +void EventManager::OnHandleDestroy(HandleType_t type, void *object) +{ + if (type == m_EventType) + { + EventInfo *pInfo = static_cast(object); + + if (pInfo->canDelete) + { + gameevents->FreeEvent(pInfo->pEvent); + delete pInfo; + } + } +} + +void EventManager::OnPluginUnloaded(IPlugin *plugin) +{ + EventHookList *pHookList; + EventHook *pHook; + + // If plugin has an event hook list... + if (plugin->GetProperty("EventHooks", reinterpret_cast(&pHookList), true)) + { + for (EventHookList::iterator iter = pHookList->begin(); iter != pHookList->end(); iter++) + { + pHook = (*iter); + + if (--pHook->refCount == 0) + { + if (pHook->pPreHook) + { + g_Forwards.ReleaseForward(pHook->pPreHook); + } + + if (pHook->pPostHook) + { + g_Forwards.ReleaseForward(pHook->pPostHook); + } + + delete pHook; + } + } + + delete pHookList; + } +} + +/* IGameEventListener2::FireGameEvent */ +void EventManager::FireGameEvent(IGameEvent *pEvent) +{ + /* Not going to do anything here. + Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */ +} + +EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode) +{ + EventHook *pHook; + + /* If we aren't listening to this event... */ + if (!gameevents->FindListener(this, name)) + { + /* Then add ourselves */ + if (!gameevents->AddListener(this, name, true)) + { + /* If event doesn't exist... */ + return EventHookErr_InvalidEvent; + } + } + + /* If a hook structure does not exist... */ + if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook)) + { + EventHookList *pHookList; + IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext()); + + /* Check plugin for an existing EventHook list */ + if (!plugin->GetProperty("EventHooks", (void **)&pHookList)) + { + pHookList = new EventHookList(); + plugin->SetProperty("EventHooks", pHookList); + } + + /* Create new GameEventHook structure */ + pHook = new EventHook(); + + if (mode == EventHookMode_Pre) + { + /* Create forward for a pre hook */ + pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS); + /* Add to forward list */ + pHook->pPreHook->AddFunction(pFunction); + } else { + /* Create forward for a post hook */ + pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS); + /* Should we copy data from a pre hook to the post hook? */ + pHook->postCopy = (mode == EventHookMode_Post); + /* Add to forward list */ + pHook->pPostHook->AddFunction(pFunction); + } + + /* Increase reference count */ + pHook->refCount++; + + /* Add hook structure to hook lists */ + pHookList->push_back(pHook); + sm_trie_insert(m_EventHooks, name, pHook); + + return EventHookErr_Okay; + } + + /* Hook structure already exists at this point */ + + if (mode == EventHookMode_Pre) + { + /* Create pre hook forward if necessary */ + if (!pHook->pPreHook) + { + pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS); + } + + /* Add plugin function to forward list */ + pHook->pPreHook->AddFunction(pFunction); + } else { + /* Create post hook forward if necessary */ + if (!pHook->pPostHook) + { + pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS); + } + + /* If postCopy is false, then we may want to set it to true */ + if (!pHook->postCopy) + { + pHook->postCopy = (mode == EventHookMode_Post); + } + + /* Add plugin function to forward list */ + pHook->pPostHook->AddFunction(pFunction); + } + + /* Increase reference count */ + pHook->refCount++; + + return EventHookErr_Okay; +} + +EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode) +{ + EventHook *pHook; + IChangeableForward **pEventForward; + + /* If hook does not exist at all */ + if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook)) + { + return EventHookErr_NotActive; + } + + /* One forward to rule them all */ + if (mode == EventHookMode_Pre) + { + pEventForward = &pHook->pPreHook; + } else { + pEventForward = &pHook->pPostHook; + } + + /* Remove function from forward's list */ + if (*pEventForward == NULL || !(*pEventForward)->RemoveFunction(pFunction)) + { + return EventHookErr_InvalidCallback; + } + + /* If forward's list contains 0 functions now, free it */ + if ((*pEventForward)->GetFunctionCount() == 0) + { + g_Forwards.ReleaseForward(*pEventForward); + *pEventForward = NULL; + } + + /* Decrement reference count */ + if (--pHook->refCount == 0) + { + /* If reference count is now 0, free hook structure */ + + EventHookList *pHookList; + IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext()); + + /* Get plugin's event hook list */ + plugin->GetProperty("EventHooks", (void**)&pHookList); + + /* Remove current structure from plugin's list */ + pHookList->remove(pHook); + + /* Delete entry in trie */ + sm_trie_delete(m_EventHooks, name); + + /* And finally free structure memory */ + delete pHook; + } + + return EventHookErr_Okay; +} + +/* IGameEventManager2::FireEvent hook */ +bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast) +{ + EventHook *pHook; + IChangeableForward *pForward; + cell_t res = Pl_Continue; + + if (!m_NotifyState) + { + RETURN_META_VALUE(MRES_IGNORED, true); + } + + /* Get the event name, we're going to need this for passing to post hooks */ + m_EventName = pEvent->GetName(); + + if (sm_trie_retrieve(m_EventHooks, m_EventName, reinterpret_cast(&pHook))) + { + pForward = pHook->pPreHook; + + if (pForward) + { + EventInfo info = {pEvent, false}; + + Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL); + pForward->PushCell(hndl); + pForward->PushString(m_EventName); + pForward->PushCell(bDontBroadcast); + pForward->Execute(&res, NULL); + + HandleSecurity sec = { NULL, g_pCoreIdent }; + g_HandleSys.FreeHandle(hndl, &sec); + } + + if (pHook->postCopy) + { + m_EventCopy = gameevents->DuplicateEvent(pEvent); + } + + if (res) + { + gameevents->FreeEvent(pEvent); + RETURN_META_VALUE(MRES_SUPERCEDE, false); + } + } + + RETURN_META_VALUE(MRES_IGNORED, true); +} + +/* IGameEventManager2::FireEvent post hook */ +bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast) +{ + EventHook *pHook; + IChangeableForward *pForward; + Handle_t hndl; + + if (!m_NotifyState) + { + m_NotifyState = true; + RETURN_META_VALUE(MRES_IGNORED, true); + } + + if (sm_trie_retrieve(m_EventHooks, m_EventName, reinterpret_cast(&pHook))) + { + pForward = pHook->pPostHook; + + if (pForward) + { + if (pHook->postCopy) + { + EventInfo info = {m_EventCopy, false}; + hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL); + pForward->PushCell(hndl); + } else { + pForward->PushCell(BAD_HANDLE); + } + + pForward->PushString(m_EventName); + pForward->PushCell(bDontBroadcast); + pForward->Execute(NULL); + + if (pHook->postCopy) + { + /* Free handle */ + HandleSecurity sec = { NULL, g_pCoreIdent }; + g_HandleSys.FreeHandle(hndl, &sec); + + /* Free event structure */ + gameevents->FreeEvent(m_EventCopy); + m_EventCopy = NULL; + } + } + } + + RETURN_META_VALUE(MRES_IGNORED, true); +} diff --git a/core/EventManager.h b/core/EventManager.h new file mode 100644 index 00000000..7b67cb00 --- /dev/null +++ b/core/EventManager.h @@ -0,0 +1,119 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $$ +*/ + +#ifndef _INCLUDE_SOURCEMOD_CGAMEEVENTMANAGER_H_ +#define _INCLUDE_SOURCEMOD_CGAMEEVENTMANAGER_H_ + +#include "sm_globals.h" +#include "sourcemm_api.h" +#include "sm_trie.h" +#include +#include +#include +#include + +using namespace SourceHook; + +//#define EVENT_PASSTHRU (1<<0) +#define EVENT_PASSTHRU_ALL (1<<1) + +struct EventInfo +{ + IGameEvent *pEvent; + bool canDelete; +}; + +struct EventHook +{ + EventHook() + { + pPreHook = NULL; + pPostHook = NULL; + postCopy = false; + refCount = 0; + } + IChangeableForward *pPreHook; + IChangeableForward *pPostHook; + bool postCopy; + unsigned int refCount; +}; + +enum EventHookMode +{ + EventHookMode_Pre, + EventHookMode_Post, + EventHookMode_PostNoCopy +}; + +enum EventHookError +{ + EventHookErr_Okay = 0, /**< No error */ + EventHookErr_InvalidEvent, /**< Specified event does not exist */ + EventHookErr_NotActive, /**< Specified event has no active hook */ + EventHookErr_InvalidCallback, /**< Specified event does not fire specified callback */ +}; + +class EventManager : + public SMGlobalClass, + public IHandleTypeDispatch, + public IPluginsListener, + public IGameEventListener2 +{ +public: + EventManager(); + ~EventManager(); +public: // SMGlobalClass + void OnSourceModAllInitialized(); + void OnSourceModShutdown(); +public: // IHandleTypeDispatch + void OnHandleDestroy(HandleType_t type, void *object); +public: // IPluginsListener + void OnPluginUnloaded(IPlugin *plugin); +public: // IGameEventListener2 + void FireGameEvent(IGameEvent *pEvent); +public: + /** + * Get the 'GameEvent' handle type ID. + */ + inline HandleType_t GetHandleType() + { + return EventManager::m_EventType; + } + + /** + * Sets the current SourceMod event notification state. + * + * If notify is set to true, SourceMod plugins will be notified of events. If false, they will not. + * This is temporarily used to make EVENT_PASSTHRU work when firing events from plugins. + */ + inline void SetNotifyState(bool notify) + { + m_NotifyState = notify; + } +public: + EventHookError HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); + EventHookError UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode=EventHookMode_Post); +private: // IGameEventManager2 hooks + bool OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast); + bool OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast); +private: + HandleType_t m_EventType; + Trie *m_EventHooks; + bool m_NotifyState; + IGameEvent *m_EventCopy; + const char *m_EventName; +}; + +extern EventManager g_EventManager; + +#endif // _INCLUDE_SOURCEMOD_CGAMEEVENTMANAGER_H_ diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index ca4676c8..f6986fa9 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -227,6 +227,10 @@ RelativePath="..\CUserMessages.cpp" > + + @@ -317,6 +321,10 @@ RelativePath="..\CUserMessages.h" > + + @@ -689,6 +697,10 @@ RelativePath="..\smn_entities.cpp" > + + diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 0c7e4570..b0889ddf 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -62,15 +62,15 @@ static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - g_ConVarManager.HookConVarChange(pContext, cvar, static_cast(params[2])); + g_ConVarManager.HookConVarChange(pContext, pConVar, static_cast(params[2])); return 1; } @@ -79,15 +79,15 @@ static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *para { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - g_ConVarManager.UnhookConVarChange(pContext, cvar, static_cast(params[2])); + g_ConVarManager.UnhookConVarChange(pContext, pConVar, static_cast(params[2])); return 1; } @@ -96,30 +96,30 @@ static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - return cvar->GetBool(); + return pConVar->GetBool(); } static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - return cvar->GetInt(); + return pConVar->GetInt(); } /* This handles both SetConVarBool() and SetConVarInt() */ @@ -127,15 +127,15 @@ static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - cvar->SetValue(params[2]); + pConVar->SetValue(params[2]); return 1; } @@ -144,15 +144,15 @@ static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - float value = cvar->GetFloat(); + float value = pConVar->GetFloat(); return sp_ftoc(value); } @@ -161,16 +161,16 @@ static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } float value = sp_ctof(params[2]); - cvar->SetValue(value); + pConVar->SetValue(value); return 1; } @@ -179,15 +179,15 @@ static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - pContext->StringToLocalUTF8(params[2], params[3], cvar->GetString(), NULL); + pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL); return 1; } @@ -196,9 +196,9 @@ static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); @@ -207,7 +207,7 @@ static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params) char *value; pContext->LocalToString(params[2], &value); - cvar->SetValue(value); + pConVar->SetValue(value); return 1; } @@ -216,30 +216,30 @@ static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - return cvar->GetFlags(); + return pConVar->GetFlags(); } static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - cvar->SetFlags(params[2]); + pConVar->SetFlags(params[2]); return 1; } @@ -248,9 +248,9 @@ static cell_t sm_GetConVarMin(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); @@ -262,7 +262,7 @@ static cell_t sm_GetConVarMin(IPluginContext *pContext, const cell_t *params) pContext->LocalToPhysAddr(params[2], &addr); - hasMin = cvar->GetMin(min); + hasMin = pConVar->GetMin(min); *addr = sp_ftoc(min); return hasMin; @@ -272,9 +272,9 @@ static cell_t sm_GetConVarMax(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); @@ -286,7 +286,7 @@ static cell_t sm_GetConVarMax(IPluginContext *pContext, const cell_t *params) pContext->LocalToPhysAddr(params[2], &addr); - hasMax = cvar->GetMax(max); + hasMax = pConVar->GetMax(max); *addr = sp_ftoc(max); return hasMax; @@ -296,15 +296,15 @@ static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - pContext->StringToLocalUTF8(params[2], params[3], cvar->GetName(), NULL); + pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL); return 1; } @@ -313,15 +313,15 @@ static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError err; - ConVar *cvar; + ConVar *pConVar; - if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&cvar)) + if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar)) != HandleError_None) { return pContext->ThrowNativeError("Invalid ConVar Handle %x (error %d)", hndl, err); } - cvar->Revert(); + pConVar->Revert(); return 1; } diff --git a/core/smn_events.cpp b/core/smn_events.cpp new file mode 100644 index 00000000..edc3b471 --- /dev/null +++ b/core/smn_events.cpp @@ -0,0 +1,337 @@ +/** +* =============================================================== +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. +* =============================================================== +* +* This file is not open source and may not be copied without explicit +* written permission of AlliedModders LLC. This file may not be redistributed +* in whole or significant part. +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php +* +* Version: $Id$ +*/ + +#include "sm_globals.h" +#include "sourcemm_api.h" +#include "HandleSys.h" +#include "EventManager.h" + +static cell_t sm_HookEvent(IPluginContext *pContext, const cell_t *params) +{ + char *name; + IPluginFunction *pFunction; + + pContext->LocalToString(params[1], &name); + pFunction = pContext->GetFunctionById(params[2]); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + if (g_EventManager.HookEvent(name, pFunction, static_cast(params[3])) == EventHookErr_InvalidEvent) + { + return pContext->ThrowNativeError("Game event \"%s\" does not exist", name); + } + + return 1; +} + +static cell_t sm_UnhookEvent(IPluginContext *pContext, const cell_t *params) +{ + char *name; + IPluginFunction *pFunction; + + pContext->LocalToString(params[1], &name); + pFunction = pContext->GetFunctionById(params[2]); + + if (!pFunction) + { + return pContext->ThrowNativeError("Invalid function id (%X)", params[2]); + } + + EventHookError err = g_EventManager.UnhookEvent(name, pFunction, static_cast(params[3])); + + /* Possible errors that UnhookGameEvent can return */ + if (err == EventHookErr_NotActive) + { + return pContext->ThrowNativeError("Game event \"%s\" has no active hook", name); + } else if (err == EventHookErr_InvalidCallback) { + return pContext->ThrowNativeError("Invalid hook callback specified for game event \"%s\"", name); + } + + return 1; +} + +static cell_t sm_CreateEvent(IPluginContext *pContext, const cell_t *params) +{ + IGameEvent *pEvent; + EventInfo *pInfo; + char *name; + + pContext->LocalToString(params[1], &name); + + pEvent = gameevents->CreateEvent(name, true); + + if (pEvent) + { + pInfo = new EventInfo; + pInfo->pEvent = pEvent; + pInfo->canDelete = true; + + return g_HandleSys.CreateHandle(g_EventManager.GetHandleType(), pInfo, pContext->GetIdentity(), g_pCoreIdent, NULL); + } + + return BAD_HANDLE; +} + +static cell_t sm_FireEvent(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + if ((params[3] & EVENT_PASSTHRU_ALL) == false) + { + /* Set whether or not SourceMod plugins should be notified */ + g_EventManager.SetNotifyState(false); + } + + /* Fire game event */ + gameevents->FireEvent(pInfo->pEvent, params[2] ? true : false); + + pInfo->canDelete = false; + + /* Free handle on game event */ + HandleSecurity sec = { pContext->GetIdentity(), g_pCoreIdent }; + g_HandleSys.FreeHandle(hndl, &sec); + + /* Free EventInfo memory */ + delete pInfo; + + return 1; +} + +static cell_t sm_CancelCreatedEvent(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + gameevents->FreeEvent(pInfo->pEvent); + + // Free GameEventInfo memory + delete pInfo; + + // Free handle on game event + HandleSecurity sec = { pContext->GetIdentity(), g_pCoreIdent }; + g_HandleSys.FreeHandle(hndl, &sec); + + return 1; +} + +static cell_t sm_GetEventName(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + pContext->StringToLocalUTF8(params[2], params[3], pInfo->pEvent->GetName(), NULL); + + return 1; +} + +static cell_t sm_GetEventBool(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + return pInfo->pEvent->GetBool(key); +} + +static cell_t sm_GetEventInt(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + return pInfo->pEvent->GetInt(key); +} + +static cell_t sm_GetEventFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + float value = pInfo->pEvent->GetFloat(key); + + return sp_ftoc(value); +} + +static cell_t sm_GetEventString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + pContext->StringToLocalUTF8(params[3], params[4], pInfo->pEvent->GetString(key), NULL); + + return 1; +} + +static cell_t sm_SetEventBool(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + pInfo->pEvent->SetBool(key, params[3] ? true : false); + + return 1; +} + +static cell_t sm_SetEventInt(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + pInfo->pEvent->SetInt(key, params[3]); + + return 1; +} + +static cell_t sm_SetEventFloat(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key; + pContext->LocalToString(params[2], &key); + + float value = sp_ctof(params[3]); + pInfo->pEvent->SetFloat(key, value); + + return 1; +} + +static cell_t sm_SetEventString(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError err; + EventInfo *pInfo; + + if ((err=g_HandleSys.ReadHandle(hndl, g_EventManager.GetHandleType(), NULL, (void **)&pInfo)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid GameEvent Handle %x (error %d)", hndl, err); + } + + char *key, *value; + pContext->LocalToString(params[2], &key); + pContext->LocalToString(params[3], &value); + + pInfo->pEvent->SetString(key, value); + + return 1; +} + +REGISTER_NATIVES(gameEventNatives) +{ + {"HookEvent", sm_HookEvent}, + {"UnhookEvent", sm_UnhookEvent}, + {"CreateEvent", sm_CreateEvent}, + {"FireEvent", sm_FireEvent}, + {"CancelCreatedEvent", sm_CancelCreatedEvent}, + {"GetEventName", sm_GetEventName}, + {"GetEventBool", sm_GetEventBool}, + {"GetEventInt", sm_GetEventInt}, + {"GetEventFloat", sm_GetEventFloat}, + {"GetEventString", sm_GetEventString}, + {"SetEventBool", sm_SetEventBool}, + {"SetEventInt", sm_SetEventInt}, + {"SetEventFloat", sm_SetEventFloat}, + {"SetEventString", sm_SetEventString}, + {NULL, NULL} +}; diff --git a/plugins/include/console.inc b/plugins/include/console.inc index c9a20c20..24fe8ef6 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -207,7 +207,7 @@ native GetCmdArgString(String:buffer[], maxlength); * @param name Name of new convar. * @param defaultValue String containing the default value of new convar. * @param helpText Optional description of the convar. - * @param flags Optional bitstream of flags determining how the convar should be handled. (See FCVAR_* constants for more details) + * @param flags Optional bitstring of flags determining how the convar should be handled. See FCVAR_* constants for more details. * @param hasMin Optional boolean that determines if the convar has a minimum value. * @param min Minimum floating point value that the convar can have if hasMin is true. * @param hasMax Optional boolean that determines if the convar has a maximum value. diff --git a/plugins/include/events.inc b/plugins/include/events.inc new file mode 100644 index 00000000..3b4cadb9 --- /dev/null +++ b/plugins/include/events.inc @@ -0,0 +1,205 @@ +/** + * vim: set ts=4 : + * =============================================================== + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. + * =============================================================== + * + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used + * or modified under the Terms and Conditions of its License Agreement, which is found + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins + * may change at any time. To view the latest information, see: + * http://www.sourcemod.net/license.php + * + * Version: $Id$ + */ + +#if defined _events_included + #endinput +#endif +#define _events_included + +/** + * Flags for firing game events + */ +#define EVENT_PASSTHRU_ALL (1<<1) /**< Event will pass through other SourceMM plugins AND SourceMod */ + +/** + * Event hook modes determining how hooking should be handled + */ +enum EventHookMode +{ + EventHookMode_Pre, /**< Hook callback fired before event is fired */ + EventHookMode_Post, /**< Hook callback fired after event is fired */ + EventHookMode_PostNoCopy /**< Hook callback fired after event is fired, but event data won't be copied */ +}; + +funcenum EventHook +{ + /** + * Called when a game event is fired. + * + * @param event Handle to event. This could be INVALID_HANDLE if every plugin hooking + * this event has set the hook mode EventHookMode_PostNoCopy. + * @param name String containing the name of the event. + * @param dontBroadcast True if event was not broadcast to clients, false otherwise. + * @return Ignored for post hooks. Plugin_Handled will block event if hooked as pre. + */ + Action:public(Handle:event, const String:name[], bool:dontBroadcast), + /** + * Called when a game event is fired. + * + * @param event Handle to event. This could be INVALID_HANDLE if every plugin hooking + * this event has set the hook mode EventHookMode_PostNoCopy. + * @param name String containing the name of the event. + * @param dontBroadcast True if event was not broadcast to clients, false otherwise. + * @noreturn + */ + public(Handle:event, const String:name[], bool:dontBroadcast), +}; + +/** + * Creates a hook for when a game event is fired. + * + * @param name Name of event. + * @param callback An EventHook function pointer. + * @param mode Optional EventHookMode determining the type of hook. + * @noreturn + * @error Invalid event name or invalid callback function. + */ +native HookEvent(const String:name[], EventHook:callback, EventHookMode:mode=EventHookMode_Post); + +/** + * Removes a hook for when a game event is fired. + * + * @param name Name of event. + * @param callback An EventHook function pointer. + * @param mode Optional EventHookMode determining the type of hook. + * @noreturn + * @error Invalid callback function or no active hook for specified event. + */ +native UnhookEvent(const String:name[], EventHook:callback, EventHookMode:mode=EventHookMode_Post); + +/** + * Creates a game event to be fired later. + * + * @param name Name of event. + * @return Handle to event or INVALID_HANDLE if event doesn't exist. + */ +native Handle:CreateEvent(const String:name[]); + +/** + * Fires a game event. + * + * @param event Handle to the event. + * @param dontBroadcast Optional boolean that determines if event should be broadcast to clients. + * @param flags Optional bitstring flags. See EVENT_* constants for more details. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native FireEvent(Handle:event, bool:dontBroadcast=false, flags=0); + +/** + * Cancels a previously created game event that has not been fired. + * + * @param event Handled to the event. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native CancelCreatedEvent(Handle:event); + +/** + * Returns the boolean value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @return The boolean value of the specfied event key. + * @error Invalid or corrupt Handle. + */ +native bool:GetEventBool(Handle:event, const String:key[]); + +/** + * Sets the boolean value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New boolean value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetEventBool(Handle:event, const String:key[], bool:value); + +/** + * Returns the integer value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @return The integer value of the specfied event key. + * @error Invalid or corrupt Handle. + */ +native GetEventInt(Handle:event, const String:key[]); + +/** + * Sets the integer value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New integer value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetEventInt(Handle:event, const String:key[], value); + +/** + * Returns the floating point value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @return The floating point value of the specfied event key. + * @error Invalid or corrupt Handle. + */ +native Float:GetEventFloat(Handle:event, const String:key[]); + +/** + * Sets the floating point value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New floating point value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetEventFloat(Handle:event, const String:key[], Float:value); + +/** + * Retrieves the string value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value Buffer to store the value of the specified event key. + * @param maxlength Maximum length of string buffer. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native GetEventString(Handle:event, const String:key[], String:value[], maxlength); + +/** + * Sets the string value of a game event's key. + * + * @param event Handle to the event. + * @param key Name of event key. + * @param value New string value. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native SetEventString(Handle:event, const String:key[], const String:value[]); + +/** + * Retrieves the name of a game event. + * + * @param event Handle to the event. + * @param value Buffer to store the name of the event. + * @param maxlength Maximum length of string buffer. + * @noreturn + * @error Invalid or corrupt Handle. + */ +native GetEventName(Handle:event, String:name[], maxlength); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 64ccb7db..4143dfb6 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -37,6 +37,8 @@ struct Plugin #include #include #include +#include +#include /** * Declare this as a struct in your plugin to expose its information. @@ -219,6 +221,5 @@ native GetGameDescription(String:buffer[], maxlength, bool:original=false); */ native GetCurrentMap(String:buffer[], maxlength); -#include #include #include