1.1 --- a/core/EventManager.cpp Fri Jul 11 06:51:21 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,461 +0,0 @@
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 "EventManager.h"
1.36 -#include "ForwardSys.h"
1.37 -#include "HandleSys.h"
1.38 -#include "PluginSys.h"
1.39 -#include "sm_stringutil.h"
1.40 -
1.41 -EventManager g_EventManager;
1.42 -
1.43 -SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool);
1.44 -
1.45 -const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell};
1.46 -typedef List<EventHook *> EventHookList;
1.47 -
1.48 -EventManager::EventManager() : m_EventType(0)
1.49 -{
1.50 - /* Create an event lookup trie */
1.51 - m_EventHooks = sm_trie_create();
1.52 -}
1.53 -
1.54 -EventManager::~EventManager()
1.55 -{
1.56 - sm_trie_destroy(m_EventHooks);
1.57 -
1.58 - /* Free memory used by EventInfo structs if any */
1.59 - CStack<EventInfo *>::iterator iter;
1.60 - for (iter = m_FreeEvents.begin(); iter != m_FreeEvents.end(); iter++)
1.61 - {
1.62 - delete (*iter);
1.63 - }
1.64 -
1.65 - m_FreeEvents.popall();
1.66 -}
1.67 -
1.68 -void EventManager::OnSourceModAllInitialized()
1.69 -{
1.70 - /* Add a hook for IGameEventManager2::FireEvent() */
1.71 - SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
1.72 - SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
1.73 -
1.74 - HandleAccess sec;
1.75 -
1.76 - /* Handle access security for 'GameEvent' handle type */
1.77 - sec.access[HandleAccess_Read] = 0;
1.78 - sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
1.79 - sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
1.80 -
1.81 - /* Create the 'GameEvent' handle type */
1.82 - m_EventType = g_HandleSys.CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
1.83 -}
1.84 -
1.85 -void EventManager::OnSourceModShutdown()
1.86 -{
1.87 - /* Remove hook for IGameEventManager2::FireEvent() */
1.88 - SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
1.89 - SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
1.90 -
1.91 - /* Remove the 'GameEvent' handle type */
1.92 - g_HandleSys.RemoveType(m_EventType, g_pCoreIdent);
1.93 -
1.94 - /* Remove ourselves as listener for events */
1.95 - gameevents->RemoveListener(this);
1.96 -}
1.97 -
1.98 -void EventManager::OnHandleDestroy(HandleType_t type, void *object)
1.99 -{
1.100 - EventInfo *pInfo = static_cast<EventInfo *>(object);
1.101 -
1.102 - /* Should only free event when created by a plugin */
1.103 - if (pInfo->pOwner)
1.104 - {
1.105 - /* Free IGameEvent */
1.106 - gameevents->FreeEvent(pInfo->pEvent);
1.107 -
1.108 - /* Add EventInfo struct to free event stack */
1.109 - m_FreeEvents.push(pInfo);
1.110 - }
1.111 -}
1.112 -
1.113 -void EventManager::OnPluginUnloaded(IPlugin *plugin)
1.114 -{
1.115 - EventHookList *pHookList;
1.116 - EventHookList::iterator iter;
1.117 - EventHook *pHook;
1.118 -
1.119 - // If plugin has an event hook list...
1.120 - if (plugin->GetProperty("EventHooks", reinterpret_cast<void **>(&pHookList), true))
1.121 - {
1.122 - for (iter = pHookList->begin(); iter != pHookList->end(); iter++)
1.123 - {
1.124 - pHook = (*iter);
1.125 -
1.126 - if (--pHook->refCount == 0)
1.127 - {
1.128 - if (pHook->pPreHook)
1.129 - {
1.130 - g_Forwards.ReleaseForward(pHook->pPreHook);
1.131 - }
1.132 -
1.133 - if (pHook->pPostHook)
1.134 - {
1.135 - g_Forwards.ReleaseForward(pHook->pPostHook);
1.136 - }
1.137 -
1.138 - delete pHook;
1.139 - }
1.140 - }
1.141 -
1.142 - delete pHookList;
1.143 - }
1.144 -}
1.145 -
1.146 -/* IGameEventListener2::FireGameEvent */
1.147 -void EventManager::FireGameEvent(IGameEvent *pEvent)
1.148 -{
1.149 - /* Not going to do anything here.
1.150 - Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
1.151 -}
1.152 -
1.153 -EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
1.154 -{
1.155 - EventHook *pHook;
1.156 -
1.157 - /* If we aren't listening to this event... */
1.158 - if (!gameevents->FindListener(this, name))
1.159 - {
1.160 - /* Then add ourselves */
1.161 - if (!gameevents->AddListener(this, name, true))
1.162 - {
1.163 - /* If event doesn't exist... */
1.164 - return EventHookErr_InvalidEvent;
1.165 - }
1.166 - }
1.167 -
1.168 - /* If a hook structure does not exist... */
1.169 - if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
1.170 - {
1.171 - EventHookList *pHookList;
1.172 - IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
1.173 -
1.174 - /* Check plugin for an existing EventHook list */
1.175 - if (!plugin->GetProperty("EventHooks", (void **)&pHookList))
1.176 - {
1.177 - pHookList = new EventHookList();
1.178 - plugin->SetProperty("EventHooks", pHookList);
1.179 - }
1.180 -
1.181 - /* Create new GameEventHook structure */
1.182 - pHook = new EventHook();
1.183 -
1.184 - if (mode == EventHookMode_Pre)
1.185 - {
1.186 - /* Create forward for a pre hook */
1.187 - pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS);
1.188 - /* Add to forward list */
1.189 - pHook->pPreHook->AddFunction(pFunction);
1.190 - } else {
1.191 - /* Create forward for a post hook */
1.192 - pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
1.193 - /* Should we copy data from a pre hook to the post hook? */
1.194 - pHook->postCopy = (mode == EventHookMode_Post);
1.195 - /* Add to forward list */
1.196 - pHook->pPostHook->AddFunction(pFunction);
1.197 - }
1.198 -
1.199 - /* Increase reference count */
1.200 - pHook->refCount++;
1.201 -
1.202 - /* Add hook structure to hook lists */
1.203 - pHookList->push_back(pHook);
1.204 - sm_trie_insert(m_EventHooks, name, pHook);
1.205 -
1.206 - return EventHookErr_Okay;
1.207 - }
1.208 -
1.209 - /* Hook structure already exists at this point */
1.210 -
1.211 - if (mode == EventHookMode_Pre)
1.212 - {
1.213 - /* Create pre hook forward if necessary */
1.214 - if (!pHook->pPreHook)
1.215 - {
1.216 - pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
1.217 - }
1.218 -
1.219 - /* Add plugin function to forward list */
1.220 - pHook->pPreHook->AddFunction(pFunction);
1.221 - } else {
1.222 - /* Create post hook forward if necessary */
1.223 - if (!pHook->pPostHook)
1.224 - {
1.225 - pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
1.226 - }
1.227 -
1.228 - /* If postCopy is false, then we may want to set it to true */
1.229 - if (!pHook->postCopy)
1.230 - {
1.231 - pHook->postCopy = (mode == EventHookMode_Post);
1.232 - }
1.233 -
1.234 - /* Add plugin function to forward list */
1.235 - pHook->pPostHook->AddFunction(pFunction);
1.236 - }
1.237 -
1.238 - /* Increase reference count */
1.239 - pHook->refCount++;
1.240 -
1.241 - return EventHookErr_Okay;
1.242 -}
1.243 -
1.244 -EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
1.245 -{
1.246 - EventHook *pHook;
1.247 - IChangeableForward **pEventForward;
1.248 -
1.249 - /* If hook does not exist at all */
1.250 - if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
1.251 - {
1.252 - return EventHookErr_NotActive;
1.253 - }
1.254 -
1.255 - /* One forward to rule them all */
1.256 - if (mode == EventHookMode_Pre)
1.257 - {
1.258 - pEventForward = &pHook->pPreHook;
1.259 - } else {
1.260 - pEventForward = &pHook->pPostHook;
1.261 - }
1.262 -
1.263 - /* Remove function from forward's list */
1.264 - if (*pEventForward == NULL || !(*pEventForward)->RemoveFunction(pFunction))
1.265 - {
1.266 - return EventHookErr_InvalidCallback;
1.267 - }
1.268 -
1.269 - /* If forward's list contains 0 functions now, free it */
1.270 - if ((*pEventForward)->GetFunctionCount() == 0)
1.271 - {
1.272 - g_Forwards.ReleaseForward(*pEventForward);
1.273 - *pEventForward = NULL;
1.274 - }
1.275 -
1.276 - /* Decrement reference count */
1.277 - if (--pHook->refCount == 0)
1.278 - {
1.279 - /* If reference count is now 0, free hook structure */
1.280 -
1.281 - EventHookList *pHookList;
1.282 - IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
1.283 -
1.284 - /* Get plugin's event hook list */
1.285 - if (!plugin->GetProperty("EventHooks", (void**)&pHookList))
1.286 - {
1.287 - return EventHookErr_NotActive;
1.288 - }
1.289 -
1.290 - /* Make sure the event was actually being hooked */
1.291 - if (pHookList->find(pHook) == pHookList->end())
1.292 - {
1.293 - return EventHookErr_NotActive;
1.294 - }
1.295 -
1.296 - /* Remove current structure from plugin's list */
1.297 - pHookList->remove(pHook);
1.298 -
1.299 - /* Delete entry in trie */
1.300 - sm_trie_delete(m_EventHooks, name);
1.301 -
1.302 - /* And finally free structure memory */
1.303 - delete pHook;
1.304 - }
1.305 -
1.306 - return EventHookErr_Okay;
1.307 -}
1.308 -
1.309 -EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name, bool force)
1.310 -{
1.311 - EventInfo *pInfo;
1.312 - IGameEvent *pEvent = gameevents->CreateEvent(name, force);
1.313 -
1.314 - if (pEvent)
1.315 - {
1.316 - if (m_FreeEvents.empty())
1.317 - {
1.318 - pInfo = new EventInfo();
1.319 - } else {
1.320 - pInfo = m_FreeEvents.front();
1.321 - m_FreeEvents.pop();
1.322 - }
1.323 -
1.324 -
1.325 - pInfo->pEvent = pEvent;
1.326 - pInfo->pOwner = pContext->GetIdentity();
1.327 -
1.328 - return pInfo;
1.329 - }
1.330 -
1.331 - return NULL;
1.332 -}
1.333 -
1.334 -void EventManager::FireEvent(EventInfo *pInfo, bool bDontBroadcast)
1.335 -{
1.336 - /* Actually fire event now */
1.337 - gameevents->FireEvent(pInfo->pEvent, bDontBroadcast);
1.338 -
1.339 - /* IGameEvent is free at this point, so no one owns this */
1.340 - pInfo->pOwner = NULL;
1.341 -
1.342 - /* Add EventInfo struct to free event stack */
1.343 - m_FreeEvents.push(pInfo);
1.344 -}
1.345 -
1.346 -void EventManager::CancelCreatedEvent(EventInfo *pInfo)
1.347 -{
1.348 - /* Free event from IGameEventManager2 */
1.349 - gameevents->FreeEvent(pInfo->pEvent);
1.350 -
1.351 - /* IGameEvent is free at this point, so no one owns this */
1.352 - pInfo->pOwner = NULL;
1.353 -
1.354 - /* Add EventInfo struct to free event stack */
1.355 - m_FreeEvents.push(pInfo);
1.356 -}
1.357 -
1.358 -/* IGameEventManager2::FireEvent hook */
1.359 -bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
1.360 -{
1.361 - EventHook *pHook;
1.362 - IChangeableForward *pForward;
1.363 - const char *name;
1.364 - cell_t res = Pl_Continue;
1.365 -
1.366 - /* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
1.367 - if (!pEvent)
1.368 - {
1.369 - RETURN_META_VALUE(MRES_IGNORED, false);
1.370 - }
1.371 -
1.372 - /* Get the event name, we're going to need this for passing to post hooks */
1.373 - name = pEvent->GetName();
1.374 -
1.375 - m_EventNames.push(name);
1.376 -
1.377 - if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
1.378 - {
1.379 - pForward = pHook->pPreHook;
1.380 -
1.381 - if (pForward)
1.382 - {
1.383 - EventInfo info = { pEvent, NULL };
1.384 -
1.385 - Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
1.386 - pForward->PushCell(hndl);
1.387 - pForward->PushString(name);
1.388 - pForward->PushCell(bDontBroadcast);
1.389 - pForward->Execute(&res, NULL);
1.390 -
1.391 - HandleSecurity sec(NULL, g_pCoreIdent);
1.392 - g_HandleSys.FreeHandle(hndl, &sec);
1.393 - }
1.394 -
1.395 - if (pHook->postCopy)
1.396 - {
1.397 - pHook->pEventCopy = gameevents->DuplicateEvent(pEvent);
1.398 - }
1.399 -
1.400 - if (res)
1.401 - {
1.402 - gameevents->FreeEvent(pEvent);
1.403 - RETURN_META_VALUE(MRES_SUPERCEDE, false);
1.404 - }
1.405 - }
1.406 -
1.407 - RETURN_META_VALUE(MRES_IGNORED, true);
1.408 -}
1.409 -
1.410 -/* IGameEventManager2::FireEvent post hook */
1.411 -bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
1.412 -{
1.413 - IGameEvent *pEventCopy = NULL;
1.414 - EventHook *pHook;
1.415 - IChangeableForward *pForward;
1.416 - const char *name;
1.417 - Handle_t hndl = 0;
1.418 -
1.419 - /* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
1.420 - if (!pEvent)
1.421 - {
1.422 - RETURN_META_VALUE(MRES_IGNORED, false);
1.423 - }
1.424 -
1.425 - name = m_EventNames.front();
1.426 -
1.427 - if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
1.428 - {
1.429 - pForward = pHook->pPostHook;
1.430 -
1.431 - if (pForward)
1.432 - {
1.433 - EventInfo info = { pHook->pEventCopy, NULL };
1.434 -
1.435 - if (pHook->postCopy)
1.436 - {
1.437 - hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
1.438 -
1.439 - pForward->PushCell(hndl);
1.440 - } else {
1.441 - pForward->PushCell(BAD_HANDLE);
1.442 - }
1.443 -
1.444 - pForward->PushString(name);
1.445 - pForward->PushCell(bDontBroadcast);
1.446 - pForward->Execute(NULL);
1.447 -
1.448 - if (pHook->postCopy)
1.449 - {
1.450 - /* Free handle */
1.451 - HandleSecurity sec(NULL, g_pCoreIdent);
1.452 - g_HandleSys.FreeHandle(hndl, &sec);
1.453 -
1.454 - /* Free event structure */
1.455 - gameevents->FreeEvent(pEventCopy);
1.456 - pHook->pEventCopy = NULL;
1.457 - }
1.458 - }
1.459 - }
1.460 -
1.461 - m_EventNames.pop();
1.462 -
1.463 - RETURN_META_VALUE(MRES_IGNORED, true);
1.464 -}