core/EventManager.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Mon May 13 14:19:17 2013 -0400 (2013-05-13)
changeset 3912 b06c6b3eec00
parent 3872 4c93f74cae51
child 4075 bf9f4d0fd9fb
permissions -rw-r--r--
Don't omit frame pointer on msvc builds.
ds@576
     1
/**
dvander@2883
     2
 * vim: set ts=4 sw=4 tw=99 noet :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
ds@3099
     5
 * Copyright (C) 2004-2010 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
ds@653
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
ds@653
    28
 *
ds@653
    29
 * Version: $Id$
ds@653
    30
 */
ds@576
    31
ds@576
    32
#include "EventManager.h"
ds@576
    33
#include "ForwardSys.h"
ds@576
    34
#include "sm_stringutil.h"
dvander@3872
    35
#include "logic_bridge.h"
ds@576
    36
ds@576
    37
EventManager g_EventManager;
ds@576
    38
ds@576
    39
SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool);
ds@576
    40
ds@582
    41
const ParamType GAMEEVENT_PARAMS[] = {Param_Cell, Param_String, Param_Cell};
ds@576
    42
typedef List<EventHook *> EventHookList;
ds@576
    43
dvander@2883
    44
class EventForwardFilter : public IForwardFilter
dvander@2883
    45
{
dvander@2883
    46
	EventInfo *pEventInfo;
dvander@2883
    47
public:
dvander@2883
    48
	EventForwardFilter(EventInfo *pEventInfo) : pEventInfo(pEventInfo)
dvander@2883
    49
	{
dvander@2883
    50
	}
dvander@2883
    51
dvander@2883
    52
	void Preprocess(IPluginFunction *fun, FwdParamInfo *params)
dvander@2883
    53
	{
dvander@2883
    54
		params[2].val = pEventInfo->bDontBroadcast ? 1 : 0;
dvander@2883
    55
	}
dvander@2883
    56
};
dvander@2883
    57
ds@712
    58
EventManager::EventManager() : m_EventType(0)
ds@576
    59
{
ds@576
    60
	/* Create an event lookup trie */
ds@576
    61
	m_EventHooks = sm_trie_create();
ds@576
    62
}
ds@576
    63
ds@576
    64
EventManager::~EventManager()
ds@576
    65
{
ds@576
    66
	sm_trie_destroy(m_EventHooks);
ds@577
    67
ds@577
    68
	/* Free memory used by EventInfo structs if any */
ds@577
    69
	CStack<EventInfo *>::iterator iter;
ds@577
    70
	for (iter = m_FreeEvents.begin(); iter != m_FreeEvents.end(); iter++)
ds@577
    71
	{
ds@577
    72
		delete (*iter);
ds@577
    73
	}
ds@577
    74
ds@577
    75
	m_FreeEvents.popall();
ds@576
    76
}
ds@576
    77
ds@576
    78
void EventManager::OnSourceModAllInitialized()
ds@576
    79
{
ds@576
    80
	/* Add a hook for IGameEventManager2::FireEvent() */
kyle@3819
    81
	SH_ADD_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent), false);
kyle@3819
    82
	SH_ADD_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent_Post), true);
ds@576
    83
ds@576
    84
	HandleAccess sec;
ds@576
    85
ds@576
    86
	/* Handle access security for 'GameEvent' handle type */
ds@576
    87
	sec.access[HandleAccess_Read] = 0;
ds@576
    88
	sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
ds@576
    89
	sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
ds@576
    90
ds@576
    91
	/* Create the 'GameEvent' handle type */
dvander@3872
    92
	m_EventType = handlesys->CreateType("GameEvent", this, 0, NULL, &sec, g_pCoreIdent, NULL);
ds@576
    93
}
ds@576
    94
ds@576
    95
void EventManager::OnSourceModShutdown()
ds@576
    96
{
ds@576
    97
	/* Remove hook for IGameEventManager2::FireEvent() */
kyle@3819
    98
	SH_REMOVE_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent), false);
kyle@3819
    99
	SH_REMOVE_HOOK(IGameEventManager2, FireEvent, gameevents, SH_MEMBER(this, &EventManager::OnFireEvent_Post), true);
ds@576
   100
ds@576
   101
	/* Remove the 'GameEvent' handle type */
dvander@3872
   102
	handlesys->RemoveType(m_EventType, g_pCoreIdent);
ds@576
   103
ds@576
   104
	/* Remove ourselves as listener for events */
ds@576
   105
	gameevents->RemoveListener(this);
ds@576
   106
}
ds@576
   107
ds@576
   108
void EventManager::OnHandleDestroy(HandleType_t type, void *object)
ds@576
   109
{
ds@577
   110
	EventInfo *pInfo = static_cast<EventInfo *>(object);
ds@576
   111
ds@577
   112
	/* Should only free event when created by a plugin */
ds@577
   113
	if (pInfo->pOwner)
ds@577
   114
	{
ds@577
   115
		/* Free IGameEvent */
ds@577
   116
		gameevents->FreeEvent(pInfo->pEvent);
ds@577
   117
ds@577
   118
		/* Add EventInfo struct to free event stack */
ds@577
   119
		m_FreeEvents.push(pInfo);
ds@576
   120
	}
ds@576
   121
}
ds@576
   122
ds@576
   123
void EventManager::OnPluginUnloaded(IPlugin *plugin)
ds@576
   124
{
ds@576
   125
	EventHookList *pHookList;
ds@582
   126
	EventHookList::iterator iter;
ds@576
   127
	EventHook *pHook;
ds@576
   128
ds@576
   129
	// If plugin has an event hook list...
ds@576
   130
	if (plugin->GetProperty("EventHooks", reinterpret_cast<void **>(&pHookList), true))
ds@576
   131
	{
ds@582
   132
		for (iter = pHookList->begin(); iter != pHookList->end(); iter++)
ds@576
   133
		{
ds@576
   134
			pHook = (*iter);
ds@576
   135
ds@576
   136
			if (--pHook->refCount == 0)
ds@576
   137
			{
ds@576
   138
				if (pHook->pPreHook)
ds@576
   139
				{
ds@576
   140
					g_Forwards.ReleaseForward(pHook->pPreHook);
ds@576
   141
				}
ds@576
   142
ds@576
   143
				if (pHook->pPostHook)
ds@576
   144
				{
ds@576
   145
					g_Forwards.ReleaseForward(pHook->pPostHook);
ds@576
   146
				}
ds@576
   147
ds@576
   148
				delete pHook;
ds@576
   149
			}
ds@576
   150
		}
ds@576
   151
ds@576
   152
		delete pHookList;
ds@576
   153
	}
ds@576
   154
}
ds@576
   155
ds@576
   156
/* IGameEventListener2::FireGameEvent */
ds@576
   157
void EventManager::FireGameEvent(IGameEvent *pEvent)
ds@576
   158
{
ds@576
   159
	/* Not going to do anything here.
ds@576
   160
	   Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
ds@576
   161
}
ds@576
   162
ds@3099
   163
#if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@3099
   164
int EventManager::GetEventDebugID()
ds@3099
   165
{
ds@3099
   166
	return EVENT_DEBUG_ID_INIT;
ds@3099
   167
}
ds@3099
   168
#endif
ds@3099
   169
ds@576
   170
EventHookError EventManager::HookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
ds@576
   171
{
ds@576
   172
	EventHook *pHook;
ds@576
   173
ds@576
   174
	/* If we aren't listening to this event... */
ds@576
   175
	if (!gameevents->FindListener(this, name))
ds@576
   176
	{
ds@576
   177
		/* Then add ourselves */
ds@576
   178
		if (!gameevents->AddListener(this, name, true))
ds@576
   179
		{
ds@576
   180
			/* If event doesn't exist... */
ds@576
   181
			return EventHookErr_InvalidEvent;
ds@576
   182
		}
ds@576
   183
	}
ds@576
   184
ds@576
   185
	/* If a hook structure does not exist... */
ds@576
   186
	if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
ds@576
   187
	{
ds@576
   188
		EventHookList *pHookList;
dvander@3872
   189
		IPlugin *plugin = scripts->FindPluginByContext(pFunction->GetParentContext()->GetContext());
ds@576
   190
ds@576
   191
		/* Check plugin for an existing EventHook list */
ds@576
   192
		if (!plugin->GetProperty("EventHooks", (void **)&pHookList))
ds@576
   193
		{
ds@576
   194
			pHookList = new EventHookList();
ds@576
   195
			plugin->SetProperty("EventHooks", pHookList);
ds@576
   196
		}
ds@576
   197
ds@576
   198
		/* Create new GameEventHook structure */
ds@576
   199
		pHook = new EventHook();
ds@576
   200
ds@576
   201
		if (mode == EventHookMode_Pre)
ds@576
   202
		{
ds@576
   203
			/* Create forward for a pre hook */
ds@890
   204
			pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Hook, 3, GAMEEVENT_PARAMS);
ds@576
   205
			/* Add to forward list */
ds@576
   206
			pHook->pPreHook->AddFunction(pFunction);
ds@576
   207
		} else {
ds@576
   208
			/* Create forward for a post hook */
ds@576
   209
			pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
ds@576
   210
			/* Should we copy data from a pre hook to the post hook? */
ds@576
   211
			pHook->postCopy = (mode == EventHookMode_Post);
ds@576
   212
			/* Add to forward list */
ds@576
   213
			pHook->pPostHook->AddFunction(pFunction);
ds@576
   214
		}
ds@576
   215
dvander@2567
   216
		/* Cache the name for post hooks */
pred@2708
   217
		pHook->name = sm_strdup(name);
dvander@2567
   218
ds@576
   219
		/* Increase reference count */
ds@576
   220
		pHook->refCount++;
ds@576
   221
ds@576
   222
		/* Add hook structure to hook lists */
ds@576
   223
		pHookList->push_back(pHook);
ds@576
   224
		sm_trie_insert(m_EventHooks, name, pHook);
ds@576
   225
ds@576
   226
		return EventHookErr_Okay;
ds@576
   227
	}
ds@576
   228
ds@576
   229
	/* Hook structure already exists at this point */
ds@576
   230
ds@576
   231
	if (mode == EventHookMode_Pre)
ds@576
   232
	{
ds@576
   233
		/* Create pre hook forward if necessary */
ds@576
   234
		if (!pHook->pPreHook)
ds@576
   235
		{
ds@576
   236
			pHook->pPreHook = g_Forwards.CreateForwardEx(NULL, ET_Event, 3, GAMEEVENT_PARAMS);
ds@576
   237
		}
ds@576
   238
ds@576
   239
		/* Add plugin function to forward list */
ds@576
   240
		pHook->pPreHook->AddFunction(pFunction);
ds@576
   241
	} else {
ds@576
   242
		/* Create post hook forward if necessary */
ds@576
   243
		if (!pHook->pPostHook)
ds@576
   244
		{
ds@576
   245
			pHook->pPostHook = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, GAMEEVENT_PARAMS);
ds@576
   246
		}
ds@576
   247
ds@576
   248
		/* If postCopy is false, then we may want to set it to true */
ds@576
   249
		if (!pHook->postCopy)
ds@576
   250
		{
ds@576
   251
			pHook->postCopy = (mode == EventHookMode_Post);
ds@576
   252
		}
ds@576
   253
ds@576
   254
		/* Add plugin function to forward list */
ds@576
   255
		pHook->pPostHook->AddFunction(pFunction);
ds@576
   256
	}
ds@576
   257
ds@576
   258
	/* Increase reference count */
ds@576
   259
	pHook->refCount++;
ds@576
   260
ds@576
   261
	return EventHookErr_Okay;
ds@576
   262
}
ds@576
   263
ds@576
   264
EventHookError EventManager::UnhookEvent(const char *name, IPluginFunction *pFunction, EventHookMode mode)
ds@576
   265
{
ds@576
   266
	EventHook *pHook;
ds@576
   267
	IChangeableForward **pEventForward;
ds@576
   268
ds@576
   269
	/* If hook does not exist at all */
ds@576
   270
	if (!sm_trie_retrieve(m_EventHooks, name, (void **)&pHook))
ds@576
   271
	{
ds@576
   272
		return EventHookErr_NotActive;
ds@576
   273
	}
ds@576
   274
ds@576
   275
	/* One forward to rule them all */
ds@576
   276
	if (mode == EventHookMode_Pre)
ds@576
   277
	{
ds@576
   278
		pEventForward = &pHook->pPreHook;
ds@576
   279
	} else {
ds@576
   280
		pEventForward = &pHook->pPostHook;
ds@576
   281
	}
ds@576
   282
ds@576
   283
	/* Remove function from forward's list */
ds@576
   284
	if (*pEventForward == NULL || !(*pEventForward)->RemoveFunction(pFunction))
ds@576
   285
	{
ds@576
   286
		return EventHookErr_InvalidCallback;
ds@576
   287
	}
ds@576
   288
ds@576
   289
	/* If forward's list contains 0 functions now, free it */
ds@576
   290
	if ((*pEventForward)->GetFunctionCount() == 0)
ds@576
   291
	{
ds@576
   292
		g_Forwards.ReleaseForward(*pEventForward);
ds@576
   293
		*pEventForward = NULL;
ds@576
   294
	}
ds@576
   295
ds@576
   296
	/* Decrement reference count */
ds@576
   297
	if (--pHook->refCount == 0)
ds@576
   298
	{
ds@576
   299
		/* If reference count is now 0, free hook structure */
ds@576
   300
ds@576
   301
		EventHookList *pHookList;
dvander@3872
   302
		IPlugin *plugin = scripts->FindPluginByContext(pFunction->GetParentContext()->GetContext());
ds@576
   303
ds@576
   304
		/* Get plugin's event hook list */
dvander@1022
   305
		if (!plugin->GetProperty("EventHooks", (void**)&pHookList))
dvander@1022
   306
		{
dvander@1022
   307
			return EventHookErr_NotActive;
dvander@1022
   308
		}
dvander@1022
   309
dvander@1022
   310
		/* Make sure the event was actually being hooked */
dvander@1022
   311
		if (pHookList->find(pHook) == pHookList->end())
dvander@1022
   312
		{
dvander@1022
   313
			return EventHookErr_NotActive;
dvander@1022
   314
		}
ds@576
   315
ds@576
   316
		/* Remove current structure from plugin's list */
ds@576
   317
		pHookList->remove(pHook);
ds@576
   318
ds@576
   319
		/* Delete entry in trie */
ds@576
   320
		sm_trie_delete(m_EventHooks, name);
ds@576
   321
dvander@2567
   322
		/* Free the cached name */
pred@2708
   323
		delete pHook->name;
dvander@2567
   324
ds@576
   325
		/* And finally free structure memory */
ds@576
   326
		delete pHook;
ds@576
   327
	}
ds@576
   328
ds@576
   329
	return EventHookErr_Okay;
ds@576
   330
}
ds@576
   331
ds@713
   332
EventInfo *EventManager::CreateEvent(IPluginContext *pContext, const char *name, bool force)
ds@577
   333
{
ds@577
   334
	EventInfo *pInfo;
ds@713
   335
	IGameEvent *pEvent = gameevents->CreateEvent(name, force);
ds@577
   336
ds@577
   337
	if (pEvent)
ds@577
   338
	{
ds@577
   339
		if (m_FreeEvents.empty())
ds@577
   340
		{
ds@577
   341
			pInfo = new EventInfo();
ds@577
   342
		} else {
ds@577
   343
			pInfo = m_FreeEvents.front();
ds@577
   344
			m_FreeEvents.pop();
ds@577
   345
		}
ds@577
   346
ds@577
   347
ds@577
   348
		pInfo->pEvent = pEvent;
ds@577
   349
		pInfo->pOwner = pContext->GetIdentity();
dvander@2883
   350
		pInfo->bDontBroadcast = false;
ds@577
   351
ds@577
   352
		return pInfo;
ds@577
   353
	}
ds@577
   354
ds@577
   355
	return NULL;
ds@577
   356
}
ds@577
   357
ds@712
   358
void EventManager::FireEvent(EventInfo *pInfo, bool bDontBroadcast)
ds@577
   359
{
ds@577
   360
	/* Actually fire event now */
ds@577
   361
	gameevents->FireEvent(pInfo->pEvent, bDontBroadcast);
ds@577
   362
ds@577
   363
	/* IGameEvent is free at this point, so no one owns this */
ds@577
   364
	pInfo->pOwner = NULL;
ds@577
   365
ds@577
   366
	/* Add EventInfo struct to free event stack */
ds@577
   367
	m_FreeEvents.push(pInfo);
ds@577
   368
}
ds@577
   369
ds@687
   370
void EventManager::CancelCreatedEvent(EventInfo *pInfo)
ds@687
   371
{
ds@687
   372
	/* Free event from IGameEventManager2 */
ds@687
   373
	gameevents->FreeEvent(pInfo->pEvent);
ds@687
   374
ds@687
   375
	/* IGameEvent is free at this point, so no one owns this */
ds@687
   376
	pInfo->pOwner = NULL;
ds@687
   377
ds@687
   378
	/* Add EventInfo struct to free event stack */
ds@687
   379
	m_FreeEvents.push(pInfo);
ds@687
   380
}
ds@687
   381
ds@576
   382
/* IGameEventManager2::FireEvent hook */
ds@576
   383
bool EventManager::OnFireEvent(IGameEvent *pEvent, bool bDontBroadcast)
ds@576
   384
{
ds@576
   385
	EventHook *pHook;
ds@576
   386
	IChangeableForward *pForward;
ds@684
   387
	const char *name;
ds@576
   388
	cell_t res = Pl_Continue;
dvander@2883
   389
	bool broadcast = bDontBroadcast;
ds@2106
   390
ds@2106
   391
	/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
ds@2106
   392
	if (!pEvent)
ds@2106
   393
	{
ds@2106
   394
		RETURN_META_VALUE(MRES_IGNORED, false);
ds@2106
   395
	}
dvander@2567
   396
ds@684
   397
	name = pEvent->GetName();
dvander@2567
   398
	
ds@684
   399
	if (sm_trie_retrieve(m_EventHooks, name, reinterpret_cast<void **>(&pHook)))
ds@576
   400
	{
dvander@2567
   401
		/* Push the event onto the event stack.  The reference count is increased to make sure 
dvander@2567
   402
		 * the structure is not garbage collected in between now and the post hook.
dvander@2567
   403
		 */
dvander@2567
   404
		pHook->refCount++;
dvander@2567
   405
		m_EventStack.push(pHook);
dvander@2567
   406
ds@576
   407
		pForward = pHook->pPreHook;
ds@576
   408
ds@576
   409
		if (pForward)
ds@576
   410
		{
ds@2538
   411
			EventInfo info(pEvent, NULL);
ds@2538
   412
			HandleSecurity sec(NULL, g_pCoreIdent);
dvander@3872
   413
			Handle_t hndl = handlesys->CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
ds@576
   414
dvander@2883
   415
			info.bDontBroadcast = bDontBroadcast;
dvander@2883
   416
dvander@2883
   417
			EventForwardFilter filter(&info);
dvander@2883
   418
ds@576
   419
			pForward->PushCell(hndl);
ds@684
   420
			pForward->PushString(name);
ds@576
   421
			pForward->PushCell(bDontBroadcast);
dvander@2883
   422
			pForward->Execute(&res, &filter);
dvander@2883
   423
dvander@2883
   424
			broadcast = info.bDontBroadcast;
ds@576
   425
dvander@3872
   426
			handlesys->FreeHandle(hndl, &sec);
ds@576
   427
		}
ds@576
   428
ds@576
   429
		if (pHook->postCopy)
ds@576
   430
		{
ds@2538
   431
			m_EventCopies.push(gameevents->DuplicateEvent(pEvent));
ds@576
   432
		}
ds@576
   433
ds@576
   434
		if (res)
ds@576
   435
		{
ds@576
   436
			gameevents->FreeEvent(pEvent);
ds@576
   437
			RETURN_META_VALUE(MRES_SUPERCEDE, false);
ds@576
   438
		}
ds@576
   439
	}
dvander@2567
   440
	else
dvander@2567
   441
	{
dvander@2567
   442
		m_EventStack.push(NULL);
dvander@2567
   443
	}
ds@576
   444
dvander@2883
   445
	if (broadcast != bDontBroadcast)
dvander@2883
   446
		RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, true, &IGameEventManager2::FireEvent, (pEvent, broadcast));
dvander@2883
   447
ds@576
   448
	RETURN_META_VALUE(MRES_IGNORED, true);
ds@576
   449
}
ds@576
   450
ds@576
   451
/* IGameEventManager2::FireEvent post hook */
ds@576
   452
bool EventManager::OnFireEvent_Post(IGameEvent *pEvent, bool bDontBroadcast)
ds@576
   453
{
ds@576
   454
	EventHook *pHook;
ds@2538
   455
	EventInfo info;
ds@576
   456
	IChangeableForward *pForward;
dvander@603
   457
	Handle_t hndl = 0;
ds@576
   458
ds@2106
   459
	/* The engine accepts NULL without crashing, so to prevent a crash in SM we ignore these */
ds@2106
   460
	if (!pEvent)
ds@2106
   461
	{
ds@2106
   462
		RETURN_META_VALUE(MRES_IGNORED, false);
ds@2106
   463
	}
ds@2106
   464
dvander@2567
   465
	pHook = m_EventStack.front();
ds@684
   466
dvander@2567
   467
	if (pHook != NULL)
ds@576
   468
	{
ds@576
   469
		pForward = pHook->pPostHook;
ds@576
   470
ds@576
   471
		if (pForward)
ds@576
   472
		{
ds@576
   473
			if (pHook->postCopy)
ds@576
   474
			{
dvander@2883
   475
				info.bDontBroadcast = bDontBroadcast;
ds@2538
   476
				info.pEvent = m_EventCopies.front();
ds@2538
   477
				info.pOwner = NULL;
dvander@3872
   478
				hndl = handlesys->CreateHandle(m_EventType, &info, NULL, g_pCoreIdent, NULL);
ds@684
   479
ds@576
   480
				pForward->PushCell(hndl);
ds@576
   481
			} else {
ds@576
   482
				pForward->PushCell(BAD_HANDLE);
ds@576
   483
			}
ds@576
   484
dvander@2567
   485
			pForward->PushString(pHook->name);
ds@576
   486
			pForward->PushCell(bDontBroadcast);
ds@576
   487
			pForward->Execute(NULL);
ds@576
   488
ds@576
   489
			if (pHook->postCopy)
ds@576
   490
			{
ds@576
   491
				/* Free handle */
dvander@857
   492
				HandleSecurity sec(NULL, g_pCoreIdent);
dvander@3872
   493
				handlesys->FreeHandle(hndl, &sec);
ds@576
   494
ds@576
   495
				/* Free event structure */
ds@2538
   496
				gameevents->FreeEvent(info.pEvent);
ds@2538
   497
				m_EventCopies.pop();
ds@576
   498
			}
ds@576
   499
		}
dvander@2567
   500
dvander@2567
   501
		/* Decrement reference count, check if a delayed delete is needed */
dvander@2567
   502
		if (--pHook->refCount == 0)
dvander@2567
   503
		{
dvander@2567
   504
			assert(pHook->pPostHook == NULL);
dvander@2567
   505
			assert(pHook->pPreHook == NULL);
dvander@2567
   506
			sm_trie_delete(m_EventHooks, pHook->name);
pred@2708
   507
			delete pHook->name;
dvander@2567
   508
			delete pHook;
dvander@2567
   509
		}
ds@576
   510
	}
ds@576
   511
dvander@2567
   512
	m_EventStack.pop();
ds@684
   513
ds@576
   514
	RETURN_META_VALUE(MRES_IGNORED, true);
ds@576
   515
}