core/UserMessages.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Sat Jan 26 12:14:40 2013 -0500 (2013-01-26)
changeset 3757 aa69f3b742c7
parent 3743 a98686a77974
child 3758 2ce920431e4a
permissions -rw-r--r--
Replaced remaining calls to old MM:S usermessages functions when using protobuf system (bug 5579, bug 5588).
dvander@592
     1
/**
ds@653
     2
 * vim: set ts=4 :
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
 */
dvander@592
    31
dvander@592
    32
#include "UserMessages.h"
ds@765
    33
#include "sm_stringutil.h"
dvander@592
    34
skamonkey@3743
    35
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
    36
#include <cstrike15_usermessage_helpers.h>
skamonkey@3743
    37
#endif
skamonkey@3743
    38
dvander@616
    39
UserMessages g_UserMsgs;
dvander@592
    40
skamonkey@3743
    41
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
    42
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
skamonkey@3743
    43
#else
ds@3099
    44
#if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
    45
SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int, const char *);
ds@2400
    46
#else
dvander@592
    47
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
ds@2400
    48
#endif
dvander@592
    49
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
skamonkey@3743
    50
#endif // ==SE_CSGO
dvander@592
    51
skamonkey@3743
    52
UserMessages::UserMessages()
skamonkey@3743
    53
#ifndef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
    54
	: m_InterceptBuffer(m_pBase, 2500)
dvander@592
    55
{
dvander@592
    56
	m_Names = sm_trie_create();
skamonkey@3743
    57
#else
skamonkey@3743
    58
	: m_InterceptBuffer(NULL)
skamonkey@3743
    59
{
skamonkey@3743
    60
#endif
dvander@592
    61
	m_HookCount = 0;
dvander@592
    62
	m_InExec = false;
dvander@592
    63
	m_InHook = false;
dvander@592
    64
	m_CurFlags = 0;
dvander@592
    65
	m_CurId = INVALID_MESSAGE_ID;
dvander@592
    66
}
dvander@592
    67
dvander@616
    68
UserMessages::~UserMessages()
dvander@592
    69
{
skamonkey@3743
    70
#ifndef USE_PROTOBUF_USERMESSAGES
dvander@592
    71
	sm_trie_destroy(m_Names);
skamonkey@3743
    72
#endif
faluco@641
    73
faluco@641
    74
	CStack<ListenerInfo *>::iterator iter;
faluco@641
    75
	for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
faluco@641
    76
	{
faluco@641
    77
		delete (*iter);
faluco@641
    78
	}
faluco@641
    79
	m_FreeListeners.popall();
dvander@592
    80
}
dvander@592
    81
ds@765
    82
void UserMessages::OnSourceModStartup(bool late)
ds@765
    83
{
skamonkey@3743
    84
#ifndef USE_PROTOBUF_USERMESSAGES
ds@765
    85
	/* -1 means SourceMM was unable to get the user message list */
ds@765
    86
	m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1);
skamonkey@3743
    87
#endif
ds@765
    88
}
ds@765
    89
dvander@616
    90
void UserMessages::OnSourceModAllInitialized()
dvander@592
    91
{
dvander@592
    92
	g_ShareSys.AddInterface(NULL, this);
dvander@592
    93
}
dvander@592
    94
dvander@616
    95
void UserMessages::OnSourceModAllShutdown()
dvander@592
    96
{
dvander@592
    97
	if (m_HookCount)
dvander@592
    98
	{
skamonkey@3743
    99
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   100
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
skamonkey@3743
   101
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
skamonkey@3743
   102
#else
dvander@616
   103
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
dvander@616
   104
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
dvander@616
   105
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
dvander@616
   106
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
skamonkey@3743
   107
#endif
dvander@592
   108
	}
dvander@592
   109
	m_HookCount = 0;
dvander@592
   110
}
dvander@592
   111
dvander@616
   112
int UserMessages::GetMessageIndex(const char *msg)
dvander@592
   113
{
skamonkey@3743
   114
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   115
	// Can split this per engine and/or game later
skamonkey@3743
   116
	return g_Cstrike15UsermessageHelpers.GetIndex(msg);
skamonkey@3743
   117
#else
dvander@592
   118
	int msgid;
ds@698
   119
dvander@592
   120
	if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
dvander@592
   121
	{
ds@765
   122
		if (m_FallbackSearch)
ds@765
   123
		{
ds@765
   124
			char msgbuf[64];
ds@765
   125
			int size;
ds@765
   126
			msgid = 0;
ds@765
   127
ds@765
   128
			while (gamedll->GetUserMessageInfo(msgid, msgbuf, sizeof(msgbuf), size))
ds@765
   129
			{
ds@765
   130
				if (strcmp(msgbuf, msg) == 0)
ds@765
   131
				{
ds@765
   132
					sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
ds@765
   133
					return msgid;
ds@765
   134
				}
ds@765
   135
				msgid++;
ds@765
   136
			}
ds@765
   137
		}
ds@765
   138
ds@698
   139
		msgid = g_SMAPI->FindUserMessage(msg);
dvander@592
   140
ds@698
   141
		if (msgid != INVALID_MESSAGE_ID)
dvander@592
   142
		{
ds@698
   143
			sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
dvander@592
   144
		}
dvander@592
   145
	}
dvander@592
   146
dvander@592
   147
	return msgid;
skamonkey@3743
   148
#endif
dvander@592
   149
}
dvander@592
   150
ds@765
   151
bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
ds@765
   152
{
skamonkey@3743
   153
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   154
	const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
skamonkey@3743
   155
	if (!pszName)
skamonkey@3743
   156
		return false;
skamonkey@3743
   157
skamonkey@3743
   158
	strncopy(buffer, pszName, maxlength);
skamonkey@3743
   159
	return true;
skamonkey@3743
   160
#else
ds@765
   161
	if (m_FallbackSearch)
ds@765
   162
	{
ds@765
   163
		int size;
ds@765
   164
		return gamedll->GetUserMessageInfo(msgid, buffer, maxlength, size);
ds@765
   165
	}
ds@766
   166
ds@765
   167
	const char *msg = g_SMAPI->GetUserMessage(msgid);
ds@765
   168
ds@765
   169
	if (msg)
ds@765
   170
	{
ds@765
   171
		strncopy(buffer, msg, maxlength);
ds@765
   172
		return true;
ds@765
   173
	}
ds@765
   174
ds@765
   175
	return false;
skamonkey@3743
   176
#endif
ds@765
   177
}
ds@765
   178
skamonkey@3743
   179
bf_write *UserMessages::StartBitBufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
dvander@592
   180
{
skamonkey@3743
   181
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   182
	return NULL;
skamonkey@3743
   183
#else
dvander@592
   184
	bf_write *buffer;
faluco@593
   185
faluco@593
   186
	if (m_InExec || m_InHook)
dvander@592
   187
	{
dvander@592
   188
		return NULL;
dvander@592
   189
	}
dvander@592
   190
	if (msg_id < 0 || msg_id >= 255)
dvander@592
   191
	{
dvander@592
   192
		return NULL;
dvander@592
   193
	}
dvander@592
   194
faluco@593
   195
	m_CellRecFilter.Initialize(players, playersNum);
dvander@592
   196
dvander@592
   197
	m_CurFlags = flags;
dvander@592
   198
	if (m_CurFlags & USERMSG_INITMSG)
dvander@592
   199
	{
faluco@593
   200
		m_CellRecFilter.SetToInit(true);
dvander@592
   201
	}
dvander@592
   202
	if (m_CurFlags & USERMSG_RELIABLE)
dvander@592
   203
	{
faluco@593
   204
		m_CellRecFilter.SetToReliable(true);
dvander@592
   205
	}
dvander@592
   206
dvander@592
   207
	m_InExec = true;
dvander@592
   208
faluco@1250
   209
	if (m_CurFlags & USERMSG_BLOCKHOOKS)
dvander@592
   210
	{
ds@3099
   211
#if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   212
		buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
ds@2400
   213
#else
faluco@1250
   214
		buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
ds@2400
   215
#endif
faluco@1250
   216
	} else {
ds@3099
   217
#if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   218
		buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
ds@2400
   219
#else
dvander@592
   220
		buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
ds@2400
   221
#endif
dvander@592
   222
	}
dvander@592
   223
dvander@592
   224
	return buffer;
skamonkey@3743
   225
#endif // USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   226
}
skamonkey@3743
   227
skamonkey@3743
   228
google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
skamonkey@3743
   229
{
skamonkey@3743
   230
#ifndef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   231
	return NULL;
skamonkey@3743
   232
#else
skamonkey@3743
   233
	protobuf::Message *buffer;
skamonkey@3743
   234
skamonkey@3743
   235
	if (m_InExec || m_InHook)
skamonkey@3743
   236
	{
skamonkey@3743
   237
		return NULL;
skamonkey@3743
   238
	}
skamonkey@3743
   239
	if (msg_id < 0 || msg_id >= 255)
skamonkey@3743
   240
	{
skamonkey@3743
   241
		return NULL;
skamonkey@3743
   242
	}
skamonkey@3743
   243
skamonkey@3743
   244
	m_CurId = msg_id;
skamonkey@3743
   245
	m_CellRecFilter.Initialize(players, playersNum);
skamonkey@3743
   246
skamonkey@3743
   247
	m_CurFlags = flags;
skamonkey@3743
   248
	if (m_CurFlags & USERMSG_INITMSG)
skamonkey@3743
   249
	{
skamonkey@3743
   250
		m_CellRecFilter.SetToInit(true);
skamonkey@3743
   251
	}
skamonkey@3743
   252
	if (m_CurFlags & USERMSG_RELIABLE)
skamonkey@3743
   253
	{
skamonkey@3743
   254
		m_CellRecFilter.SetToReliable(true);
skamonkey@3743
   255
	}
skamonkey@3743
   256
skamonkey@3743
   257
	m_InExec = true;
skamonkey@3743
   258
skamonkey@3743
   259
	if (m_CurFlags & USERMSG_BLOCKHOOKS)
skamonkey@3743
   260
	{
skamonkey@3743
   261
		// direct message creation, return buffer "from engine". keep track
skamonkey@3743
   262
		m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
skamonkey@3743
   263
		buffer = m_FakeEngineBuffer;
skamonkey@3743
   264
	} else {
skamonkey@3757
   265
		char messageName[32];
skamonkey@3757
   266
		if (!GetMessageName(msg_id, messageName, sizeof(messageName)))
skamonkey@3757
   267
		{
skamonkey@3757
   268
			m_InExec = false;
skamonkey@3757
   269
			return NULL;
skamonkey@3757
   270
		}
skamonkey@3757
   271
skamonkey@3757
   272
		protobuf::Message *msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
skamonkey@3743
   273
		switch (m_FakeMetaRes)
skamonkey@3743
   274
		{
skamonkey@3743
   275
		case MRES_IGNORED:
skamonkey@3743
   276
		case MRES_HANDLED:
skamonkey@3743
   277
			m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
skamonkey@3743
   278
			buffer = m_FakeEngineBuffer;
skamonkey@3743
   279
			break;		
skamonkey@3743
   280
skamonkey@3743
   281
		case MRES_OVERRIDE:
skamonkey@3743
   282
			m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
skamonkey@3743
   283
		// fallthrough
skamonkey@3743
   284
		case MRES_SUPERCEDE:
skamonkey@3743
   285
			buffer = msg;
skamonkey@3743
   286
			break;
skamonkey@3743
   287
		}
skamonkey@3743
   288
		
skamonkey@3757
   289
		OnStartMessage_Post(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
skamonkey@3743
   290
	}
skamonkey@3743
   291
skamonkey@3743
   292
	return buffer;
skamonkey@3743
   293
#endif // USE_PROTOBUF_USERMESSAGES
dvander@592
   294
}
dvander@592
   295
dvander@616
   296
bool UserMessages::EndMessage()
dvander@592
   297
{
dvander@592
   298
	if (!m_InExec)
dvander@592
   299
	{
dvander@592
   300
		return false;
dvander@592
   301
	}
dvander@592
   302
skamonkey@3743
   303
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   304
	if (m_CurFlags & USERMSG_BLOCKHOOKS)
skamonkey@3743
   305
	{
skamonkey@3743
   306
		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
skamonkey@3743
   307
		delete m_FakeEngineBuffer;
skamonkey@3743
   308
		m_FakeEngineBuffer = NULL;
skamonkey@3743
   309
	} else {
skamonkey@3743
   310
		OnMessageEnd_Pre();
skamonkey@3743
   311
skamonkey@3743
   312
		switch (m_FakeMetaRes)
skamonkey@3743
   313
		{
skamonkey@3743
   314
		case MRES_IGNORED:
skamonkey@3743
   315
		case MRES_HANDLED:
skamonkey@3743
   316
		case MRES_OVERRIDE:
skamonkey@3743
   317
			engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
skamonkey@3743
   318
			delete m_FakeEngineBuffer;
skamonkey@3743
   319
			m_FakeEngineBuffer = NULL;
skamonkey@3743
   320
			break;
skamonkey@3743
   321
		//case MRES_SUPERCEDE:
skamonkey@3743
   322
		}
skamonkey@3743
   323
skamonkey@3743
   324
		OnMessageEnd_Post();
skamonkey@3743
   325
	}
skamonkey@3743
   326
#else
faluco@1250
   327
	if (m_CurFlags & USERMSG_BLOCKHOOKS)
dvander@592
   328
	{
faluco@1250
   329
		ENGINE_CALL(MessageEnd)();
faluco@1250
   330
	} else {
dvander@592
   331
		engine->MessageEnd();
dvander@592
   332
	}
skamonkey@3743
   333
#endif // SE_CSGO
dvander@592
   334
dvander@592
   335
	m_InExec = false;
dvander@592
   336
	m_CurFlags = 0;
faluco@593
   337
	m_CellRecFilter.Reset();
dvander@592
   338
dvander@592
   339
	return true;
dvander@592
   340
}
dvander@592
   341
skamonkey@3743
   342
UserMessageType UserMessages::GetUserMessageType() const
skamonkey@3743
   343
{
skamonkey@3743
   344
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   345
	return UM_Protobuf;
skamonkey@3743
   346
#else
skamonkey@3743
   347
	return UM_BitBuf;
skamonkey@3743
   348
#endif
skamonkey@3743
   349
}
skamonkey@3743
   350
dvander@2636
   351
bool UserMessages::HookUserMessage2(int msg_id,
dvander@2636
   352
									IUserMessageListener *pListener,
dvander@2636
   353
									bool intercept)
dvander@2636
   354
{
skamonkey@3743
   355
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   356
	return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
skamonkey@3743
   357
#else
skamonkey@3743
   358
	return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
skamonkey@3743
   359
#endif
dvander@2636
   360
}
dvander@2636
   361
dvander@2636
   362
bool UserMessages::UnhookUserMessage2(int msg_id,
dvander@2636
   363
									  IUserMessageListener *pListener,
dvander@2636
   364
									  bool intercept)
dvander@2636
   365
{
skamonkey@3743
   366
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   367
	return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
skamonkey@3743
   368
#else
skamonkey@3743
   369
	return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
skamonkey@3743
   370
#endif
dvander@2636
   371
}
dvander@2636
   372
dvander@616
   373
bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
dvander@592
   374
{
skamonkey@3743
   375
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   376
	return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
skamonkey@3743
   377
#else
skamonkey@3743
   378
	return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
skamonkey@3743
   379
#endif
dvander@2636
   380
}
dvander@2636
   381
dvander@2636
   382
bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
dvander@2636
   383
{	
skamonkey@3743
   384
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   385
	return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
skamonkey@3743
   386
#else
skamonkey@3743
   387
	return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
skamonkey@3743
   388
#endif
dvander@2636
   389
}
dvander@2636
   390
skamonkey@3743
   391
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   392
bool UserMessages::InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743
   393
#else
skamonkey@3743
   394
bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743
   395
#endif
dvander@2636
   396
{
dvander@592
   397
	if (msg_id < 0 || msg_id >= 255)
dvander@592
   398
	{
dvander@592
   399
		return false;
dvander@592
   400
	}
dvander@592
   401
faluco@593
   402
	ListenerInfo *pInfo;
faluco@593
   403
	if (m_FreeListeners.empty())
faluco@593
   404
	{
faluco@593
   405
		pInfo = new ListenerInfo;
faluco@593
   406
	} else {
faluco@593
   407
		pInfo = m_FreeListeners.front();
faluco@593
   408
		m_FreeListeners.pop();
faluco@593
   409
	}
faluco@593
   410
faluco@593
   411
	pInfo->Callback = pListener;
faluco@593
   412
	pInfo->IsHooked = false;
faluco@593
   413
	pInfo->KillMe = false;
dvander@2636
   414
	pInfo->IsNew = isNew;
faluco@593
   415
dvander@592
   416
	if (!m_HookCount++)
dvander@592
   417
	{
skamonkey@3743
   418
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   419
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
skamonkey@3743
   420
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
skamonkey@3743
   421
#else
dvander@616
   422
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
dvander@616
   423
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
dvander@616
   424
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
dvander@616
   425
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
skamonkey@3743
   426
#endif
dvander@592
   427
	}
dvander@592
   428
dvander@592
   429
	if (intercept)
dvander@592
   430
	{
faluco@593
   431
		m_msgIntercepts[msg_id].push_back(pInfo);
dvander@592
   432
	} else {
faluco@593
   433
		m_msgHooks[msg_id].push_back(pInfo);
dvander@592
   434
	}
dvander@592
   435
dvander@592
   436
	return true;
dvander@592
   437
}
dvander@592
   438
skamonkey@3743
   439
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   440
bool UserMessages::InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743
   441
#else
skamonkey@3743
   442
bool UserMessages::InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743
   443
#endif
dvander@2636
   444
{
faluco@593
   445
	MsgList *pList;
dvander@592
   446
	MsgIter iter;
faluco@593
   447
	ListenerInfo *pInfo;
dvander@592
   448
	bool deleted = false;
dvander@592
   449
dvander@592
   450
	if (msg_id < 0 || msg_id >= 255)
dvander@592
   451
	{
dvander@592
   452
		return false;
dvander@592
   453
	}
dvander@592
   454
faluco@593
   455
	pList = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
faluco@593
   456
	for (iter=pList->begin(); iter!=pList->end(); iter++)
dvander@592
   457
	{
faluco@593
   458
		pInfo = (*iter);
dvander@2636
   459
		if (pInfo->Callback == pListener && pInfo->IsNew == isNew)
dvander@592
   460
		{
faluco@593
   461
			if (pInfo->IsHooked)
faluco@593
   462
			{
faluco@593
   463
				pInfo->KillMe = true;
faluco@593
   464
				return true;
faluco@593
   465
			}
faluco@593
   466
			pList->erase(iter);
dvander@592
   467
			deleted = true;
dvander@592
   468
			break;
dvander@592
   469
		}
dvander@592
   470
	}
dvander@592
   471
faluco@593
   472
	if (deleted)
faluco@593
   473
	{
faluco@593
   474
		_DecRefCounter();
faluco@593
   475
	}
faluco@593
   476
faluco@593
   477
	return deleted;
faluco@593
   478
}
faluco@593
   479
dvander@616
   480
void UserMessages::_DecRefCounter()
faluco@593
   481
{
faluco@593
   482
	if (--m_HookCount == 0)
dvander@592
   483
	{
skamonkey@3743
   484
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   485
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
skamonkey@3743
   486
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
skamonkey@3743
   487
#else
dvander@616
   488
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
dvander@616
   489
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
dvander@616
   490
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
dvander@616
   491
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
skamonkey@3743
   492
#endif
dvander@592
   493
	}
dvander@592
   494
}
dvander@592
   495
skamonkey@3743
   496
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   497
// Unlike protobuf's Message::CopyFrom:
skamonkey@3743
   498
// - Does not require to/from message descriptors to be identical.
skamonkey@3743
   499
// - Fields are copied by name, rather than index.
skamonkey@3743
   500
// - String fields are retrieved for copy with GetStringReference, to avoid destucting libprotobuf std::string in sm.
skamonkey@3743
   501
// - Unknown fields in |from| message are not copied to |to| message.
skamonkey@3743
   502
// - Copying Message fields recursively calls this function, rather than Message::MergeFrom.
skamonkey@3743
   503
static void _CopyProtobufMessage(const protobuf::Message &from, protobuf::Message *to)
skamonkey@3743
   504
{
skamonkey@3743
   505
	const protobuf::Descriptor* descriptor = from.GetDescriptor();
skamonkey@3743
   506
skamonkey@3743
   507
	const protobuf::Reflection* from_reflection = from.GetReflection();
skamonkey@3743
   508
	const protobuf::Reflection* to_reflection = to->GetReflection();
skamonkey@3743
   509
skamonkey@3743
   510
	protobuf::UnknownFieldSet toUnknownFields;
skamonkey@3743
   511
skamonkey@3743
   512
	int fromFieldCount = descriptor->field_count();
skamonkey@3743
   513
	for (int i = 0; i < fromFieldCount; i++)
skamonkey@3743
   514
	{
skamonkey@3743
   515
		const protobuf::FieldDescriptor* fromField = descriptor->field(i);
skamonkey@3743
   516
		const protobuf::FieldDescriptor* toField = to->GetDescriptor()->FindFieldByName(fromField->name());
skamonkey@3743
   517
skamonkey@3743
   518
		// This will stripped new fields off of intercepted usermessages.
skamonkey@3743
   519
		// TODO: fix that.
skamonkey@3743
   520
		if (!toField)
skamonkey@3743
   521
		{
skamonkey@3743
   522
			continue;
skamonkey@3743
   523
		}
skamonkey@3743
   524
skamonkey@3743
   525
		if (fromField->is_repeated())
skamonkey@3743
   526
		{
skamonkey@3743
   527
			int count = from_reflection->FieldSize(from, fromField);
skamonkey@3743
   528
			for (int j = 0; j < count; j++)
skamonkey@3743
   529
			{
skamonkey@3743
   530
				switch (fromField->cpp_type())
skamonkey@3743
   531
				{
skamonkey@3743
   532
#define HANDLE_TYPE(CPPTYPE, METHOD)                                           \
skamonkey@3743
   533
				case protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE:             \
skamonkey@3743
   534
					to_reflection->Add##METHOD(to, toField,                    \
skamonkey@3743
   535
					from_reflection->GetRepeated##METHOD(from, fromField, j)); \
skamonkey@3743
   536
					break;
skamonkey@3743
   537
				HANDLE_TYPE(INT32 , Int32 );
skamonkey@3743
   538
				HANDLE_TYPE(INT64 , Int64 );
skamonkey@3743
   539
				HANDLE_TYPE(UINT32, UInt32);
skamonkey@3743
   540
				HANDLE_TYPE(UINT64, UInt64);
skamonkey@3743
   541
				HANDLE_TYPE(FLOAT , Float );
skamonkey@3743
   542
				HANDLE_TYPE(DOUBLE, Double);
skamonkey@3743
   543
				HANDLE_TYPE(BOOL  , Bool  );
skamonkey@3743
   544
				HANDLE_TYPE(ENUM  , Enum  );
skamonkey@3743
   545
#undef HANDLE_TYPE
skamonkey@3743
   546
				case protobuf::FieldDescriptor::CPPTYPE_STRING:
skamonkey@3743
   547
					{
skamonkey@3743
   548
						std::string buffer;
skamonkey@3743
   549
						to_reflection->AddString(to, toField,
skamonkey@3743
   550
							from_reflection->GetRepeatedStringReference(from, fromField, j, &buffer));
skamonkey@3743
   551
					}
skamonkey@3743
   552
					break;
skamonkey@3743
   553
				case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
skamonkey@3743
   554
					_CopyProtobufMessage(
skamonkey@3743
   555
						from_reflection->GetRepeatedMessage(from, fromField, j),
skamonkey@3743
   556
						to_reflection->AddMessage(to, toField)
skamonkey@3743
   557
						);
skamonkey@3743
   558
					break;
skamonkey@3743
   559
				}
skamonkey@3743
   560
			}
skamonkey@3743
   561
		}
skamonkey@3743
   562
		else
skamonkey@3743
   563
		{
skamonkey@3743
   564
			switch (fromField->cpp_type())
skamonkey@3743
   565
			{
skamonkey@3743
   566
#define HANDLE_TYPE(CPPTYPE, METHOD)                            \
skamonkey@3743
   567
			case protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE:  \
skamonkey@3743
   568
				to_reflection->Set##METHOD(to, toField,         \
skamonkey@3743
   569
				from_reflection->Get##METHOD(from, fromField)); \
skamonkey@3743
   570
				break;
skamonkey@3743
   571
			HANDLE_TYPE(INT32 , Int32 );
skamonkey@3743
   572
			HANDLE_TYPE(INT64 , Int64 );
skamonkey@3743
   573
			HANDLE_TYPE(UINT32, UInt32);
skamonkey@3743
   574
			HANDLE_TYPE(UINT64, UInt64);
skamonkey@3743
   575
			HANDLE_TYPE(FLOAT , Float );
skamonkey@3743
   576
			HANDLE_TYPE(DOUBLE, Double);
skamonkey@3743
   577
			HANDLE_TYPE(BOOL  , Bool  );
skamonkey@3743
   578
			HANDLE_TYPE(ENUM  , Enum  );
skamonkey@3743
   579
#undef HANDLE_TYPE
skamonkey@3743
   580
			case protobuf::FieldDescriptor::CPPTYPE_STRING:
skamonkey@3743
   581
				{
skamonkey@3743
   582
					std::string buffer;
skamonkey@3743
   583
					to_reflection->SetString(to, toField,
skamonkey@3743
   584
						from_reflection->GetStringReference(from, fromField, &buffer));
skamonkey@3743
   585
				}
skamonkey@3743
   586
				break;
skamonkey@3743
   587
			case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
skamonkey@3743
   588
				_CopyProtobufMessage(
skamonkey@3743
   589
					from_reflection->GetMessage(from, fromField),
skamonkey@3743
   590
					to_reflection->MutableMessage(to, toField)
skamonkey@3743
   591
					);
skamonkey@3743
   592
				break;
skamonkey@3743
   593
			}
skamonkey@3743
   594
		}
skamonkey@3743
   595
	}
skamonkey@3743
   596
}
skamonkey@3743
   597
#endif
skamonkey@3743
   598
skamonkey@3743
   599
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   600
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
skamonkey@3743
   601
{
skamonkey@3743
   602
	OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
skamonkey@3743
   603
	if (m_FakeMetaRes == MRES_SUPERCEDE)
skamonkey@3743
   604
	{
skamonkey@3743
   605
		_CopyProtobufMessage(msg, m_InterceptBuffer);
skamonkey@3743
   606
	}
skamonkey@3743
   607
	else
skamonkey@3743
   608
	{
skamonkey@3743
   609
		OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
skamonkey@3743
   610
	}
skamonkey@3743
   611
skamonkey@3743
   612
	OnMessageEnd_Pre();
skamonkey@3743
   613
	if (m_FakeMetaRes == MRES_SUPERCEDE)
skamonkey@3743
   614
		RETURN_META(MRES_SUPERCEDE);
skamonkey@3743
   615
skamonkey@3743
   616
	RETURN_META(MRES_IGNORED);
skamonkey@3743
   617
}
skamonkey@3743
   618
skamonkey@3743
   619
void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
skamonkey@3743
   620
{
skamonkey@3743
   621
	OnMessageEnd_Post();
skamonkey@3743
   622
	RETURN_META(MRES_IGNORED);
skamonkey@3743
   623
}
skamonkey@3743
   624
#endif
skamonkey@3743
   625
skamonkey@3743
   626
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   627
#define UM_RETURN_META_VALUE(res, val) \
skamonkey@3743
   628
	m_FakeMetaRes = res;               \
skamonkey@3743
   629
	return val;
skamonkey@3743
   630
skamonkey@3743
   631
#define UM_RETURN_META(res)            \
skamonkey@3743
   632
	m_FakeMetaRes = res;               \
skamonkey@3743
   633
	return;
skamonkey@3743
   634
#else
skamonkey@3743
   635
#define UM_RETURN_META_VALUE(res, val) \
skamonkey@3743
   636
	RETURN_META_VALUE(res, val)
skamonkey@3743
   637
skamonkey@3743
   638
#define UM_RETURN_META(res)            \
skamonkey@3743
   639
	RETURN_META(res)
skamonkey@3743
   640
#endif
skamonkey@3743
   641
skamonkey@3743
   642
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   643
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
skamonkey@3743
   644
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   645
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
ds@2400
   646
#else
dvander@616
   647
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
ds@2400
   648
#endif
dvander@592
   649
{
dvander@592
   650
	bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
dvander@592
   651
	bool is_hook_empty = m_msgHooks[msg_type].empty();
dvander@592
   652
faluco@593
   653
	if ((is_intercept_empty && is_hook_empty)
faluco@1250
   654
		|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
dvander@592
   655
	{
dvander@592
   656
		m_InHook = false;
skamonkey@3743
   657
		UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   658
	}
dvander@592
   659
dvander@592
   660
	m_CurId = msg_type;
dvander@592
   661
	m_CurRecFilter = filter;
dvander@592
   662
	m_InHook = true;
faluco@597
   663
	m_BlockEndPost = false;
dvander@592
   664
dvander@592
   665
	if (!is_intercept_empty)
dvander@592
   666
	{
skamonkey@3743
   667
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   668
		if (m_InterceptBuffer)
skamonkey@3743
   669
			delete m_InterceptBuffer;
skamonkey@3743
   670
		m_InterceptBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
skamonkey@3743
   671
		UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
skamonkey@3743
   672
#else
faluco@593
   673
		m_InterceptBuffer.Reset();
skamonkey@3743
   674
		UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
skamonkey@3743
   675
#endif
dvander@592
   676
	}
dvander@592
   677
skamonkey@3743
   678
	UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   679
}
dvander@592
   680
skamonkey@3743
   681
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   682
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
skamonkey@3743
   683
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   684
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
ds@2400
   685
#else
dvander@616
   686
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
ds@2400
   687
#endif
dvander@592
   688
{
dvander@592
   689
	if (!m_InHook)
dvander@592
   690
	{
skamonkey@3743
   691
		UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   692
	}
dvander@592
   693
skamonkey@3743
   694
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   695
	m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
skamonkey@3743
   696
	m_OrigBuffer = m_FakeEngineBuffer;
skamonkey@3743
   697
#else
dvander@592
   698
	m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
skamonkey@3743
   699
#endif
dvander@592
   700
skamonkey@3743
   701
	UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   702
}
dvander@592
   703
dvander@616
   704
void UserMessages::OnMessageEnd_Post()
dvander@592
   705
{
dvander@2636
   706
	if (!m_InHook)
dvander@592
   707
	{
skamonkey@3743
   708
		UM_RETURN_META(MRES_IGNORED);
dvander@592
   709
	}
dvander@592
   710
faluco@593
   711
	MsgList *pList;
dvander@592
   712
	MsgIter iter;
faluco@593
   713
	ListenerInfo *pInfo;
faluco@593
   714
pred@2577
   715
	m_InHook = false;
pred@2577
   716
faluco@593
   717
	pList = &m_msgIntercepts[m_CurId];
faluco@593
   718
	for (iter=pList->begin(); iter!=pList->end(); )
faluco@593
   719
	{
faluco@593
   720
		pInfo = (*iter);
dvander@2636
   721
		if (m_BlockEndPost && !pInfo->IsNew)
dvander@2636
   722
		{
dvander@2636
   723
			continue;
dvander@2636
   724
		}
faluco@593
   725
		pInfo->IsHooked = true;
faluco@593
   726
		pInfo->Callback->OnUserMessageSent(m_CurId);
dvander@2636
   727
		if (pInfo->IsNew)
dvander@2636
   728
		{
dvander@2636
   729
			pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
dvander@2636
   730
		}
dvander@592
   731
faluco@593
   732
		if (pInfo->KillMe)
faluco@593
   733
		{
faluco@593
   734
			iter = pList->erase(iter);
faluco@593
   735
			m_FreeListeners.push(pInfo);
faluco@593
   736
			_DecRefCounter();
faluco@593
   737
			continue;
faluco@593
   738
		}
faluco@593
   739
faluco@593
   740
		pInfo->IsHooked = false;
faluco@593
   741
		iter++;
dvander@592
   742
	}
dvander@592
   743
faluco@593
   744
	pList = &m_msgHooks[m_CurId];
faluco@594
   745
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   746
	{
faluco@593
   747
		pInfo = (*iter);
dvander@2636
   748
		if (m_BlockEndPost && !pInfo->IsNew)
dvander@2636
   749
		{
dvander@2636
   750
			continue;
dvander@2636
   751
		}
faluco@594
   752
		pInfo->IsHooked = true;
faluco@593
   753
		pInfo->Callback->OnUserMessageSent(m_CurId);
dvander@2636
   754
		if (pInfo->IsNew)
dvander@2636
   755
		{
dvander@2636
   756
			pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
dvander@2636
   757
		}
faluco@593
   758
faluco@593
   759
		if (pInfo->KillMe)
faluco@593
   760
		{
faluco@593
   761
			iter = pList->erase(iter);
faluco@593
   762
			m_FreeListeners.push(pInfo);
faluco@593
   763
			_DecRefCounter();
faluco@593
   764
			continue;
faluco@593
   765
		}
faluco@593
   766
faluco@593
   767
		pInfo->IsHooked = false;
faluco@593
   768
		iter++;
dvander@592
   769
	}
dvander@592
   770
}
dvander@592
   771
dvander@616
   772
void UserMessages::OnMessageEnd_Pre()
dvander@592
   773
{
dvander@592
   774
	if (!m_InHook)
dvander@592
   775
	{
skamonkey@3743
   776
		UM_RETURN_META(MRES_IGNORED);
dvander@592
   777
	}
dvander@592
   778
faluco@593
   779
	MsgList *pList;
dvander@592
   780
	MsgIter iter;
faluco@593
   781
	ListenerInfo *pInfo;
faluco@593
   782
dvander@592
   783
	ResultType res;
dvander@592
   784
	bool intercepted = false;
dvander@592
   785
	bool handled = false;
dvander@592
   786
faluco@593
   787
	pList = &m_msgIntercepts[m_CurId];
faluco@593
   788
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   789
	{
faluco@593
   790
		pInfo = (*iter);
faluco@593
   791
		pInfo->IsHooked = true;
skamonkey@3743
   792
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   793
		res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
skamonkey@3743
   794
#else
faluco@593
   795
		res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
skamonkey@3743
   796
#endif
faluco@593
   797
faluco@597
   798
		intercepted = true;
faluco@597
   799
faluco@593
   800
		switch (res)
dvander@592
   801
		{
faluco@593
   802
		case Pl_Stop:
faluco@593
   803
			{
faluco@593
   804
				if (pInfo->KillMe)
faluco@593
   805
				{
faluco@593
   806
					pList->erase(iter);
faluco@593
   807
					m_FreeListeners.push(pInfo);
faluco@593
   808
					_DecRefCounter();
faluco@593
   809
					goto supercede;
faluco@593
   810
				}
faluco@593
   811
				pInfo->IsHooked = false;
faluco@593
   812
				goto supercede;
faluco@593
   813
			}
faluco@593
   814
		case Pl_Handled:
faluco@593
   815
			{
faluco@593
   816
				handled = true;
faluco@593
   817
				if (pInfo->KillMe)
faluco@593
   818
				{
faluco@593
   819
					iter = pList->erase(iter);
faluco@593
   820
					m_FreeListeners.push(pInfo);
faluco@593
   821
					_DecRefCounter();
faluco@593
   822
					continue;
faluco@593
   823
				}
faluco@593
   824
				break;
faluco@593
   825
			}
faluco@593
   826
		default:
faluco@593
   827
			{
faluco@593
   828
				if (pInfo->KillMe)
faluco@593
   829
				{
faluco@593
   830
					iter = pList->erase(iter);
faluco@593
   831
					m_FreeListeners.push(pInfo);
faluco@593
   832
					_DecRefCounter();
faluco@593
   833
					continue;
faluco@593
   834
				}
faluco@597
   835
				break;
faluco@593
   836
			}
dvander@592
   837
		}
faluco@593
   838
		pInfo->IsHooked = false;
faluco@593
   839
		iter++;
dvander@592
   840
	}
dvander@592
   841
dvander@2734
   842
	if (!handled && intercepted)
dvander@592
   843
	{
skamonkey@3743
   844
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   845
		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
skamonkey@3743
   846
		delete m_InterceptBuffer;
skamonkey@3743
   847
		m_InterceptBuffer = NULL;
skamonkey@3743
   848
#else
faluco@593
   849
		bf_write *engine_bfw;
ds@3099
   850
#if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   851
		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId));
ds@2400
   852
#else
dvander@592
   853
		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
ds@2400
   854
#endif
dvander@592
   855
		m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
dvander@592
   856
		engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
dvander@592
   857
		ENGINE_CALL(MessageEnd)();
skamonkey@3743
   858
#endif // SE_CSGO
dvander@592
   859
	}
dvander@592
   860
faluco@593
   861
	pList = &m_msgHooks[m_CurId];
faluco@593
   862
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   863
	{
faluco@593
   864
		pInfo = (*iter);
faluco@593
   865
		pInfo->IsHooked = true;
faluco@593
   866
		pInfo->Callback->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
faluco@593
   867
faluco@593
   868
		if (pInfo->KillMe)
faluco@593
   869
		{
faluco@593
   870
			iter = pList->erase(iter);
faluco@593
   871
			m_FreeListeners.push(pInfo);
faluco@593
   872
			_DecRefCounter();
faluco@593
   873
			continue;
faluco@593
   874
		}
faluco@593
   875
faluco@594
   876
		pInfo->IsHooked = false;
faluco@593
   877
		iter++;
dvander@592
   878
	}
dvander@592
   879
skamonkey@3743
   880
	UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
dvander@592
   881
supercede:
faluco@597
   882
	m_BlockEndPost = true;
skamonkey@3743
   883
	UM_RETURN_META(MRES_SUPERCEDE);
dvander@592
   884
}