Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.
(This day shall henceforth be known as the Eighty Column Massacre of '07)
3 * =============================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "EventManager.h"
33 #include "ForwardSys.h"
34 #include "HandleSys.h"
35 #include "PluginSys.h"
36 #include "sm_stringutil.h"
38 EventManager g_EventManager;
40 SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool);
42 const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell};
43 typedef List<EventHook *> EventHookList;
45 EventManager::EventManager() : m_EventType(0)
47 /* Create an event lookup trie */
48 m_EventHooks = sm_trie_create();
51 EventManager::~EventManager()
53 sm_trie_destroy(m_EventHooks);
55 /* Free memory used by EventInfo structs if any */
56 CStack<EventInfo *>::iterator iter;
57 for (iter = m_FreeEvents.begin(); iter != m_FreeEvents.end(); iter++)
62 m_FreeEvents.popall();
65 void EventManager::OnSourceModAllInitialized()
67 /* Add a hook for IGameEventManager2::FireEvent() */
68 SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
69 SH_ADD_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
73 /* Handle access security for 'GameEvent' handle type */
74 sec.access[HandleAccess_Read] = 0;
75 sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
76 sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
78 /* Create the 'GameEvent' handle type */
79 m_EventType = g_HandleSys.CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
82 void EventManager::OnSourceModShutdown()
84 /* Remove hook for IGameEventManager2::FireEvent() */
85 SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent, false);
86 SH_REMOVE_HOOK_MEMFUNC(IGameEventManager2, FireEvent, gameevents, this, &EventManager::OnFireEvent_Post, true);
88 /* Remove the 'GameEvent' handle type */
89 g_HandleSys.RemoveType(m_EventType, g_pCoreIdent);
91 /* Remove ourselves as listener for events */
92 gameevents->RemoveListener(this);
95 void EventManager::OnHandleDestroy(HandleType_t type, void *object)
97 EventInfo *pInfo = static_cast<EventInfo *>(object);
99 /* Should only free event when created by a plugin */
102 /* Free IGameEvent */
103 gameevents->FreeEvent(pInfo->pEvent);
105 /* Add EventInfo struct to free event stack */
106 m_FreeEvents.push(pInfo);
110 void EventManager::OnPluginUnloaded(IPlugin *plugin)
112 EventHookList *pHookList;
113 EventHookList::iterator iter;
116 // If plugin has an event hook list...
117 if (plugin->GetProperty("EventHooks", reinterpret_cast<void **>(&pHookList), true))
119 for (iter = pHookList->begin(); iter != pHookList->end(); iter++)
123 if (--pHook->refCount == 0)
127 g_Forwards.ReleaseForward(pHook->pPreHook);
130 if (pHook->pPostHook)
132 g_Forwards.ReleaseForward(pHook->pPostHook);
143 /* IGameEventListener2::FireGameEvent */
144 void EventManager::FireGameEvent(IGameEvent *pEvent)
146 /* Not going to do anything here.
147 Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
150 EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
154 /* If we aren't listening to this event... */
155 if (!gameevents->FindListener(this, name))
157 /* Then add ourselves */
158 if (!gameevents->AddListener(this, name, true))
160 /* If event doesn't exist... */
161 return EventHookErr_InvalidEvent;
165 /* If a hook structure does not exist... */
166 if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
168 EventHookList *pHookList;
169 IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
171 /* Check plugin for an existing EventHook list */
172 if (!plugin->GetProperty("EventHooks", (void **)&pHookList))
174 pHookList = new EventHookList();
175 plugin->SetProperty("EventHooks", pHookList);
178 /* Create new GameEventHook structure */
179 pHook = new EventHook();
181 if (mode == EventHookMode_Pre)
183 /* Create forward for a pre hook */
184 pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS);
185 /* Add to forward list */
186 pHook->pPreHook->AddFunction(pFunction);
188 /* Create forward for a post hook */
189 pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
190 /* Should we copy data from a pre hook to the post hook? */
191 pHook->postCopy = (mode == EventHookMode_Post);
192 /* Add to forward list */
193 pHook->pPostHook->AddFunction(pFunction);
196 /* Increase reference count */
199 /* Add hook structure to hook lists */
200 pHookList->push_back(pHook);
201 sm_trie_insert(m_EventHooks, name, pHook);
203 return EventHookErr_Okay;
206 /* Hook structure already exists at this point */
208 if (mode == EventHookMode_Pre)
210 /* Create pre hook forward if necessary */
211 if (!pHook->pPreHook)
213 pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
216 /* Add plugin function to forward list */
217 pHook->pPreHook->AddFunction(pFunction);
219 /* Create post hook forward if necessary */
220 if (!pHook->pPostHook)
222 pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
225 /* If postCopy is false, then we may want to set it to true */
226 if (!pHook->postCopy)
228 pHook->postCopy = (mode == EventHookMode_Post);
231 /* Add plugin function to forward list */
232 pHook->pPostHook->AddFunction(pFunction);
235 /* Increase reference count */
238 return EventHookErr_Okay;
241 EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
244 IChangeableForward **pEventForward;
246 /* If hook does not exist at all */
247 if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
249 return EventHookErr_NotActive;
252 /* One forward to rule them all */
253 if (mode == EventHookMode_Pre)
255 pEventForward = &pHook->pPreHook;
257 pEventForward = &pHook->pPostHook;
260 /* Remove function from forward's list */
261 if (*pEventForward == NULL || !(*pEventForward)->RemoveFunction(pFunction))
263 return EventHookErr_InvalidCallback;
266 /* If forward's list contains 0 functions now, free it */
267 if ((*pEventForward)->GetFunctionCount() == 0)
269 g_Forwards.ReleaseForward(*pEventForward);
270 *pEventForward = NULL;
273 /* Decrement reference count */
274 if (--pHook->refCount == 0)
276 /* If reference count is now 0, free hook structure */
278 EventHookList *pHookList;
279 IPlugin *plugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
281 /* Get plugin's event hook list */
282 if (!plugin->GetProperty("EventHooks", (void**)&pHookList))
284 return EventHookErr_NotActive;
287 /* Make sure the event was actually being hooked */
288 if (pHookList->find(pHook) == pHookList->end())
290 return EventHookErr_NotActive;
293 /* Remove current structure from plugin's list */
294 pHookList->remove(pHook);
296 /* Delete entry in trie */
297 sm_trie_delete(m_EventHooks, name);
299 /* And finally free structure memory */
303 return EventHookErr_Okay;
306 EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name, bool force)
309 IGameEvent *pEvent = gameevents->CreateEvent(name, force);
313 if (m_FreeEvents.empty())
315 pInfo = new EventInfo();
317 pInfo = m_FreeEvents.front();
322 pInfo->pEvent = pEvent;
323 pInfo->pOwner = pContext->GetIdentity();
331 void EventManager::FireEvent(EventInfo *pInfo, bool bDontBroadcast)
333 /* Actually fire event now */
334 gameevents->FireEvent(pInfo->pEvent, bDontBroadcast);
336 /* IGameEvent is free at this point, so no one owns this */
337 pInfo->pOwner = NULL;
339 /* Add EventInfo struct to free event stack */
340 m_FreeEvents.push(pInfo);
343 void EventManager::CancelCreatedEvent(EventInfo *pInfo)
345 /* Free event from IGameEventManager2 */
346 gameevents->FreeEvent(pInfo->pEvent);
348 /* IGameEvent is free at this point, so no one owns this */
349 pInfo->pOwner = NULL;
351 /* Add EventInfo struct to free event stack */
352 m_FreeEvents.push(pInfo);
355 /* IGameEventManager2::FireEvent hook */
356 bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
359 IChangeableForward *pForward;
361 cell_t res = Pl_Continue;
363 /* Get the event name, we're going to need this for passing to post hooks */
364 name = pEvent->GetName();
366 m_EventNames.push(name);
368 if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
370 pForward = pHook->pPreHook;
374 EventInfo info = { pEvent, NULL };
376 Handle_t hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
377 pForward->PushCell(hndl);
378 pForward->PushString(name);
379 pForward->PushCell(bDontBroadcast);
380 pForward->Execute(&res, NULL);
382 HandleSecurity sec(NULL, g_pCoreIdent);
383 g_HandleSys.FreeHandle(hndl, &sec);
388 pHook->pEventCopy = gameevents->DuplicateEvent(pEvent);
393 gameevents->FreeEvent(pEvent);
394 RETURN_META_VALUE(MRES_SUPERCEDE, false);
398 RETURN_META_VALUE(MRES_IGNORED, true);
401 /* IGameEventManager2::FireEvent post hook */
402 bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
404 IGameEvent *pEventCopy = NULL;
406 IChangeableForward *pForward;
410 name = m_EventNames.front();
412 if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
414 pForward = pHook->pPostHook;
418 EventInfo info = { pHook->pEventCopy, NULL };
422 hndl = g_HandleSys.CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
424 pForward->PushCell(hndl);
426 pForward->PushCell(BAD_HANDLE);
429 pForward->PushString(name);
430 pForward->PushCell(bDontBroadcast);
431 pForward->Execute(NULL);
436 HandleSecurity sec(NULL, g_pCoreIdent);
437 g_HandleSys.FreeHandle(hndl, &sec);
439 /* Free event structure */
440 gameevents->FreeEvent(pEventCopy);
441 pHook->pEventCopy = NULL;
448 RETURN_META_VALUE(MRES_IGNORED, true);