core/UserMessages.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Tue Jan 22 23:18:27 2013 -0500 (2013-01-22)
changeset 3749 4dc3d723c490
parent 3743 a98686a77974
child 3757 aa69f3b742c7
permissions -rw-r--r--
Triggering build against new mac libprotobuf.
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@3743
   265
		protobuf::Message *msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
skamonkey@3743
   266
		switch (m_FakeMetaRes)
skamonkey@3743
   267
		{
skamonkey@3743
   268
		case MRES_IGNORED:
skamonkey@3743
   269
		case MRES_HANDLED:
skamonkey@3743
   270
			m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
skamonkey@3743
   271
			buffer = m_FakeEngineBuffer;
skamonkey@3743
   272
			break;		
skamonkey@3743
   273
skamonkey@3743
   274
		case MRES_OVERRIDE:
skamonkey@3743
   275
			m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
skamonkey@3743
   276
		// fallthrough
skamonkey@3743
   277
		case MRES_SUPERCEDE:
skamonkey@3743
   278
			buffer = msg;
skamonkey@3743
   279
			break;
skamonkey@3743
   280
		}
skamonkey@3743
   281
		
skamonkey@3743
   282
		OnStartMessage_Post(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
skamonkey@3743
   283
	}
skamonkey@3743
   284
skamonkey@3743
   285
	return buffer;
skamonkey@3743
   286
#endif // USE_PROTOBUF_USERMESSAGES
dvander@592
   287
}
dvander@592
   288
dvander@616
   289
bool UserMessages::EndMessage()
dvander@592
   290
{
dvander@592
   291
	if (!m_InExec)
dvander@592
   292
	{
dvander@592
   293
		return false;
dvander@592
   294
	}
dvander@592
   295
skamonkey@3743
   296
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   297
	if (m_CurFlags & USERMSG_BLOCKHOOKS)
skamonkey@3743
   298
	{
skamonkey@3743
   299
		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
skamonkey@3743
   300
		delete m_FakeEngineBuffer;
skamonkey@3743
   301
		m_FakeEngineBuffer = NULL;
skamonkey@3743
   302
	} else {
skamonkey@3743
   303
		OnMessageEnd_Pre();
skamonkey@3743
   304
skamonkey@3743
   305
		switch (m_FakeMetaRes)
skamonkey@3743
   306
		{
skamonkey@3743
   307
		case MRES_IGNORED:
skamonkey@3743
   308
		case MRES_HANDLED:
skamonkey@3743
   309
		case MRES_OVERRIDE:
skamonkey@3743
   310
			engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
skamonkey@3743
   311
			delete m_FakeEngineBuffer;
skamonkey@3743
   312
			m_FakeEngineBuffer = NULL;
skamonkey@3743
   313
			break;
skamonkey@3743
   314
		//case MRES_SUPERCEDE:
skamonkey@3743
   315
		}
skamonkey@3743
   316
skamonkey@3743
   317
		OnMessageEnd_Post();
skamonkey@3743
   318
	}
skamonkey@3743
   319
#else
faluco@1250
   320
	if (m_CurFlags & USERMSG_BLOCKHOOKS)
dvander@592
   321
	{
faluco@1250
   322
		ENGINE_CALL(MessageEnd)();
faluco@1250
   323
	} else {
dvander@592
   324
		engine->MessageEnd();
dvander@592
   325
	}
skamonkey@3743
   326
#endif // SE_CSGO
dvander@592
   327
dvander@592
   328
	m_InExec = false;
dvander@592
   329
	m_CurFlags = 0;
faluco@593
   330
	m_CellRecFilter.Reset();
dvander@592
   331
dvander@592
   332
	return true;
dvander@592
   333
}
dvander@592
   334
skamonkey@3743
   335
UserMessageType UserMessages::GetUserMessageType() const
skamonkey@3743
   336
{
skamonkey@3743
   337
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   338
	return UM_Protobuf;
skamonkey@3743
   339
#else
skamonkey@3743
   340
	return UM_BitBuf;
skamonkey@3743
   341
#endif
skamonkey@3743
   342
}
skamonkey@3743
   343
dvander@2636
   344
bool UserMessages::HookUserMessage2(int msg_id,
dvander@2636
   345
									IUserMessageListener *pListener,
dvander@2636
   346
									bool intercept)
dvander@2636
   347
{
skamonkey@3743
   348
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   349
	return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
skamonkey@3743
   350
#else
skamonkey@3743
   351
	return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
skamonkey@3743
   352
#endif
dvander@2636
   353
}
dvander@2636
   354
dvander@2636
   355
bool UserMessages::UnhookUserMessage2(int msg_id,
dvander@2636
   356
									  IUserMessageListener *pListener,
dvander@2636
   357
									  bool intercept)
dvander@2636
   358
{
skamonkey@3743
   359
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   360
	return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
skamonkey@3743
   361
#else
skamonkey@3743
   362
	return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
skamonkey@3743
   363
#endif
dvander@2636
   364
}
dvander@2636
   365
dvander@616
   366
bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
dvander@592
   367
{
skamonkey@3743
   368
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   369
	return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
skamonkey@3743
   370
#else
skamonkey@3743
   371
	return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
skamonkey@3743
   372
#endif
dvander@2636
   373
}
dvander@2636
   374
dvander@2636
   375
bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
dvander@2636
   376
{	
skamonkey@3743
   377
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   378
	return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
skamonkey@3743
   379
#else
skamonkey@3743
   380
	return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
skamonkey@3743
   381
#endif
dvander@2636
   382
}
dvander@2636
   383
skamonkey@3743
   384
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   385
bool UserMessages::InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743
   386
#else
skamonkey@3743
   387
bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743
   388
#endif
dvander@2636
   389
{
dvander@592
   390
	if (msg_id < 0 || msg_id >= 255)
dvander@592
   391
	{
dvander@592
   392
		return false;
dvander@592
   393
	}
dvander@592
   394
faluco@593
   395
	ListenerInfo *pInfo;
faluco@593
   396
	if (m_FreeListeners.empty())
faluco@593
   397
	{
faluco@593
   398
		pInfo = new ListenerInfo;
faluco@593
   399
	} else {
faluco@593
   400
		pInfo = m_FreeListeners.front();
faluco@593
   401
		m_FreeListeners.pop();
faluco@593
   402
	}
faluco@593
   403
faluco@593
   404
	pInfo->Callback = pListener;
faluco@593
   405
	pInfo->IsHooked = false;
faluco@593
   406
	pInfo->KillMe = false;
dvander@2636
   407
	pInfo->IsNew = isNew;
faluco@593
   408
dvander@592
   409
	if (!m_HookCount++)
dvander@592
   410
	{
skamonkey@3743
   411
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   412
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
skamonkey@3743
   413
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
skamonkey@3743
   414
#else
dvander@616
   415
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
dvander@616
   416
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
dvander@616
   417
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
dvander@616
   418
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
skamonkey@3743
   419
#endif
dvander@592
   420
	}
dvander@592
   421
dvander@592
   422
	if (intercept)
dvander@592
   423
	{
faluco@593
   424
		m_msgIntercepts[msg_id].push_back(pInfo);
dvander@592
   425
	} else {
faluco@593
   426
		m_msgHooks[msg_id].push_back(pInfo);
dvander@592
   427
	}
dvander@592
   428
dvander@592
   429
	return true;
dvander@592
   430
}
dvander@592
   431
skamonkey@3743
   432
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   433
bool UserMessages::InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743
   434
#else
skamonkey@3743
   435
bool UserMessages::InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743
   436
#endif
dvander@2636
   437
{
faluco@593
   438
	MsgList *pList;
dvander@592
   439
	MsgIter iter;
faluco@593
   440
	ListenerInfo *pInfo;
dvander@592
   441
	bool deleted = false;
dvander@592
   442
dvander@592
   443
	if (msg_id < 0 || msg_id >= 255)
dvander@592
   444
	{
dvander@592
   445
		return false;
dvander@592
   446
	}
dvander@592
   447
faluco@593
   448
	pList = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
faluco@593
   449
	for (iter=pList->begin(); iter!=pList->end(); iter++)
dvander@592
   450
	{
faluco@593
   451
		pInfo = (*iter);
dvander@2636
   452
		if (pInfo->Callback == pListener && pInfo->IsNew == isNew)
dvander@592
   453
		{
faluco@593
   454
			if (pInfo->IsHooked)
faluco@593
   455
			{
faluco@593
   456
				pInfo->KillMe = true;
faluco@593
   457
				return true;
faluco@593
   458
			}
faluco@593
   459
			pList->erase(iter);
dvander@592
   460
			deleted = true;
dvander@592
   461
			break;
dvander@592
   462
		}
dvander@592
   463
	}
dvander@592
   464
faluco@593
   465
	if (deleted)
faluco@593
   466
	{
faluco@593
   467
		_DecRefCounter();
faluco@593
   468
	}
faluco@593
   469
faluco@593
   470
	return deleted;
faluco@593
   471
}
faluco@593
   472
dvander@616
   473
void UserMessages::_DecRefCounter()
faluco@593
   474
{
faluco@593
   475
	if (--m_HookCount == 0)
dvander@592
   476
	{
skamonkey@3743
   477
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   478
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
skamonkey@3743
   479
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
skamonkey@3743
   480
#else
dvander@616
   481
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
dvander@616
   482
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
dvander@616
   483
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
dvander@616
   484
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
skamonkey@3743
   485
#endif
dvander@592
   486
	}
dvander@592
   487
}
dvander@592
   488
skamonkey@3743
   489
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   490
// Unlike protobuf's Message::CopyFrom:
skamonkey@3743
   491
// - Does not require to/from message descriptors to be identical.
skamonkey@3743
   492
// - Fields are copied by name, rather than index.
skamonkey@3743
   493
// - String fields are retrieved for copy with GetStringReference, to avoid destucting libprotobuf std::string in sm.
skamonkey@3743
   494
// - Unknown fields in |from| message are not copied to |to| message.
skamonkey@3743
   495
// - Copying Message fields recursively calls this function, rather than Message::MergeFrom.
skamonkey@3743
   496
static void _CopyProtobufMessage(const protobuf::Message &from, protobuf::Message *to)
skamonkey@3743
   497
{
skamonkey@3743
   498
	const protobuf::Descriptor* descriptor = from.GetDescriptor();
skamonkey@3743
   499
skamonkey@3743
   500
	const protobuf::Reflection* from_reflection = from.GetReflection();
skamonkey@3743
   501
	const protobuf::Reflection* to_reflection = to->GetReflection();
skamonkey@3743
   502
skamonkey@3743
   503
	protobuf::UnknownFieldSet toUnknownFields;
skamonkey@3743
   504
skamonkey@3743
   505
	int fromFieldCount = descriptor->field_count();
skamonkey@3743
   506
	for (int i = 0; i < fromFieldCount; i++)
skamonkey@3743
   507
	{
skamonkey@3743
   508
		const protobuf::FieldDescriptor* fromField = descriptor->field(i);
skamonkey@3743
   509
		const protobuf::FieldDescriptor* toField = to->GetDescriptor()->FindFieldByName(fromField->name());
skamonkey@3743
   510
skamonkey@3743
   511
		// This will stripped new fields off of intercepted usermessages.
skamonkey@3743
   512
		// TODO: fix that.
skamonkey@3743
   513
		if (!toField)
skamonkey@3743
   514
		{
skamonkey@3743
   515
			continue;
skamonkey@3743
   516
		}
skamonkey@3743
   517
skamonkey@3743
   518
		if (fromField->is_repeated())
skamonkey@3743
   519
		{
skamonkey@3743
   520
			int count = from_reflection->FieldSize(from, fromField);
skamonkey@3743
   521
			for (int j = 0; j < count; j++)
skamonkey@3743
   522
			{
skamonkey@3743
   523
				switch (fromField->cpp_type())
skamonkey@3743
   524
				{
skamonkey@3743
   525
#define HANDLE_TYPE(CPPTYPE, METHOD)                                           \
skamonkey@3743
   526
				case protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE:             \
skamonkey@3743
   527
					to_reflection->Add##METHOD(to, toField,                    \
skamonkey@3743
   528
					from_reflection->GetRepeated##METHOD(from, fromField, j)); \
skamonkey@3743
   529
					break;
skamonkey@3743
   530
				HANDLE_TYPE(INT32 , Int32 );
skamonkey@3743
   531
				HANDLE_TYPE(INT64 , Int64 );
skamonkey@3743
   532
				HANDLE_TYPE(UINT32, UInt32);
skamonkey@3743
   533
				HANDLE_TYPE(UINT64, UInt64);
skamonkey@3743
   534
				HANDLE_TYPE(FLOAT , Float );
skamonkey@3743
   535
				HANDLE_TYPE(DOUBLE, Double);
skamonkey@3743
   536
				HANDLE_TYPE(BOOL  , Bool  );
skamonkey@3743
   537
				HANDLE_TYPE(ENUM  , Enum  );
skamonkey@3743
   538
#undef HANDLE_TYPE
skamonkey@3743
   539
				case protobuf::FieldDescriptor::CPPTYPE_STRING:
skamonkey@3743
   540
					{
skamonkey@3743
   541
						std::string buffer;
skamonkey@3743
   542
						to_reflection->AddString(to, toField,
skamonkey@3743
   543
							from_reflection->GetRepeatedStringReference(from, fromField, j, &buffer));
skamonkey@3743
   544
					}
skamonkey@3743
   545
					break;
skamonkey@3743
   546
				case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
skamonkey@3743
   547
					_CopyProtobufMessage(
skamonkey@3743
   548
						from_reflection->GetRepeatedMessage(from, fromField, j),
skamonkey@3743
   549
						to_reflection->AddMessage(to, toField)
skamonkey@3743
   550
						);
skamonkey@3743
   551
					break;
skamonkey@3743
   552
				}
skamonkey@3743
   553
			}
skamonkey@3743
   554
		}
skamonkey@3743
   555
		else
skamonkey@3743
   556
		{
skamonkey@3743
   557
			switch (fromField->cpp_type())
skamonkey@3743
   558
			{
skamonkey@3743
   559
#define HANDLE_TYPE(CPPTYPE, METHOD)                            \
skamonkey@3743
   560
			case protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE:  \
skamonkey@3743
   561
				to_reflection->Set##METHOD(to, toField,         \
skamonkey@3743
   562
				from_reflection->Get##METHOD(from, fromField)); \
skamonkey@3743
   563
				break;
skamonkey@3743
   564
			HANDLE_TYPE(INT32 , Int32 );
skamonkey@3743
   565
			HANDLE_TYPE(INT64 , Int64 );
skamonkey@3743
   566
			HANDLE_TYPE(UINT32, UInt32);
skamonkey@3743
   567
			HANDLE_TYPE(UINT64, UInt64);
skamonkey@3743
   568
			HANDLE_TYPE(FLOAT , Float );
skamonkey@3743
   569
			HANDLE_TYPE(DOUBLE, Double);
skamonkey@3743
   570
			HANDLE_TYPE(BOOL  , Bool  );
skamonkey@3743
   571
			HANDLE_TYPE(ENUM  , Enum  );
skamonkey@3743
   572
#undef HANDLE_TYPE
skamonkey@3743
   573
			case protobuf::FieldDescriptor::CPPTYPE_STRING:
skamonkey@3743
   574
				{
skamonkey@3743
   575
					std::string buffer;
skamonkey@3743
   576
					to_reflection->SetString(to, toField,
skamonkey@3743
   577
						from_reflection->GetStringReference(from, fromField, &buffer));
skamonkey@3743
   578
				}
skamonkey@3743
   579
				break;
skamonkey@3743
   580
			case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
skamonkey@3743
   581
				_CopyProtobufMessage(
skamonkey@3743
   582
					from_reflection->GetMessage(from, fromField),
skamonkey@3743
   583
					to_reflection->MutableMessage(to, toField)
skamonkey@3743
   584
					);
skamonkey@3743
   585
				break;
skamonkey@3743
   586
			}
skamonkey@3743
   587
		}
skamonkey@3743
   588
	}
skamonkey@3743
   589
}
skamonkey@3743
   590
#endif
skamonkey@3743
   591
skamonkey@3743
   592
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   593
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
skamonkey@3743
   594
{
skamonkey@3743
   595
	OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
skamonkey@3743
   596
	if (m_FakeMetaRes == MRES_SUPERCEDE)
skamonkey@3743
   597
	{
skamonkey@3743
   598
		_CopyProtobufMessage(msg, m_InterceptBuffer);
skamonkey@3743
   599
	}
skamonkey@3743
   600
	else
skamonkey@3743
   601
	{
skamonkey@3743
   602
		OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
skamonkey@3743
   603
	}
skamonkey@3743
   604
skamonkey@3743
   605
	OnMessageEnd_Pre();
skamonkey@3743
   606
	if (m_FakeMetaRes == MRES_SUPERCEDE)
skamonkey@3743
   607
		RETURN_META(MRES_SUPERCEDE);
skamonkey@3743
   608
skamonkey@3743
   609
	RETURN_META(MRES_IGNORED);
skamonkey@3743
   610
}
skamonkey@3743
   611
skamonkey@3743
   612
void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
skamonkey@3743
   613
{
skamonkey@3743
   614
	OnMessageEnd_Post();
skamonkey@3743
   615
	RETURN_META(MRES_IGNORED);
skamonkey@3743
   616
}
skamonkey@3743
   617
#endif
skamonkey@3743
   618
skamonkey@3743
   619
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   620
#define UM_RETURN_META_VALUE(res, val) \
skamonkey@3743
   621
	m_FakeMetaRes = res;               \
skamonkey@3743
   622
	return val;
skamonkey@3743
   623
skamonkey@3743
   624
#define UM_RETURN_META(res)            \
skamonkey@3743
   625
	m_FakeMetaRes = res;               \
skamonkey@3743
   626
	return;
skamonkey@3743
   627
#else
skamonkey@3743
   628
#define UM_RETURN_META_VALUE(res, val) \
skamonkey@3743
   629
	RETURN_META_VALUE(res, val)
skamonkey@3743
   630
skamonkey@3743
   631
#define UM_RETURN_META(res)            \
skamonkey@3743
   632
	RETURN_META(res)
skamonkey@3743
   633
#endif
skamonkey@3743
   634
skamonkey@3743
   635
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   636
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
skamonkey@3743
   637
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   638
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
ds@2400
   639
#else
dvander@616
   640
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
ds@2400
   641
#endif
dvander@592
   642
{
dvander@592
   643
	bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
dvander@592
   644
	bool is_hook_empty = m_msgHooks[msg_type].empty();
dvander@592
   645
faluco@593
   646
	if ((is_intercept_empty && is_hook_empty)
faluco@1250
   647
		|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
dvander@592
   648
	{
dvander@592
   649
		m_InHook = false;
skamonkey@3743
   650
		UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   651
	}
dvander@592
   652
dvander@592
   653
	m_CurId = msg_type;
dvander@592
   654
	m_CurRecFilter = filter;
dvander@592
   655
	m_InHook = true;
faluco@597
   656
	m_BlockEndPost = false;
dvander@592
   657
dvander@592
   658
	if (!is_intercept_empty)
dvander@592
   659
	{
skamonkey@3743
   660
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   661
		if (m_InterceptBuffer)
skamonkey@3743
   662
			delete m_InterceptBuffer;
skamonkey@3743
   663
		m_InterceptBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
skamonkey@3743
   664
		UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
skamonkey@3743
   665
#else
faluco@593
   666
		m_InterceptBuffer.Reset();
skamonkey@3743
   667
		UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
skamonkey@3743
   668
#endif
dvander@592
   669
	}
dvander@592
   670
skamonkey@3743
   671
	UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   672
}
dvander@592
   673
skamonkey@3743
   674
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   675
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
skamonkey@3743
   676
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   677
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
ds@2400
   678
#else
dvander@616
   679
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
ds@2400
   680
#endif
dvander@592
   681
{
dvander@592
   682
	if (!m_InHook)
dvander@592
   683
	{
skamonkey@3743
   684
		UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   685
	}
dvander@592
   686
skamonkey@3743
   687
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   688
	m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
skamonkey@3743
   689
	m_OrigBuffer = m_FakeEngineBuffer;
skamonkey@3743
   690
#else
dvander@592
   691
	m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
skamonkey@3743
   692
#endif
dvander@592
   693
skamonkey@3743
   694
	UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   695
}
dvander@592
   696
dvander@616
   697
void UserMessages::OnMessageEnd_Post()
dvander@592
   698
{
dvander@2636
   699
	if (!m_InHook)
dvander@592
   700
	{
skamonkey@3743
   701
		UM_RETURN_META(MRES_IGNORED);
dvander@592
   702
	}
dvander@592
   703
faluco@593
   704
	MsgList *pList;
dvander@592
   705
	MsgIter iter;
faluco@593
   706
	ListenerInfo *pInfo;
faluco@593
   707
pred@2577
   708
	m_InHook = false;
pred@2577
   709
faluco@593
   710
	pList = &m_msgIntercepts[m_CurId];
faluco@593
   711
	for (iter=pList->begin(); iter!=pList->end(); )
faluco@593
   712
	{
faluco@593
   713
		pInfo = (*iter);
dvander@2636
   714
		if (m_BlockEndPost && !pInfo->IsNew)
dvander@2636
   715
		{
dvander@2636
   716
			continue;
dvander@2636
   717
		}
faluco@593
   718
		pInfo->IsHooked = true;
faluco@593
   719
		pInfo->Callback->OnUserMessageSent(m_CurId);
dvander@2636
   720
		if (pInfo->IsNew)
dvander@2636
   721
		{
dvander@2636
   722
			pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
dvander@2636
   723
		}
dvander@592
   724
faluco@593
   725
		if (pInfo->KillMe)
faluco@593
   726
		{
faluco@593
   727
			iter = pList->erase(iter);
faluco@593
   728
			m_FreeListeners.push(pInfo);
faluco@593
   729
			_DecRefCounter();
faluco@593
   730
			continue;
faluco@593
   731
		}
faluco@593
   732
faluco@593
   733
		pInfo->IsHooked = false;
faluco@593
   734
		iter++;
dvander@592
   735
	}
dvander@592
   736
faluco@593
   737
	pList = &m_msgHooks[m_CurId];
faluco@594
   738
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   739
	{
faluco@593
   740
		pInfo = (*iter);
dvander@2636
   741
		if (m_BlockEndPost && !pInfo->IsNew)
dvander@2636
   742
		{
dvander@2636
   743
			continue;
dvander@2636
   744
		}
faluco@594
   745
		pInfo->IsHooked = true;
faluco@593
   746
		pInfo->Callback->OnUserMessageSent(m_CurId);
dvander@2636
   747
		if (pInfo->IsNew)
dvander@2636
   748
		{
dvander@2636
   749
			pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
dvander@2636
   750
		}
faluco@593
   751
faluco@593
   752
		if (pInfo->KillMe)
faluco@593
   753
		{
faluco@593
   754
			iter = pList->erase(iter);
faluco@593
   755
			m_FreeListeners.push(pInfo);
faluco@593
   756
			_DecRefCounter();
faluco@593
   757
			continue;
faluco@593
   758
		}
faluco@593
   759
faluco@593
   760
		pInfo->IsHooked = false;
faluco@593
   761
		iter++;
dvander@592
   762
	}
dvander@592
   763
}
dvander@592
   764
dvander@616
   765
void UserMessages::OnMessageEnd_Pre()
dvander@592
   766
{
dvander@592
   767
	if (!m_InHook)
dvander@592
   768
	{
skamonkey@3743
   769
		UM_RETURN_META(MRES_IGNORED);
dvander@592
   770
	}
dvander@592
   771
faluco@593
   772
	MsgList *pList;
dvander@592
   773
	MsgIter iter;
faluco@593
   774
	ListenerInfo *pInfo;
faluco@593
   775
dvander@592
   776
	ResultType res;
dvander@592
   777
	bool intercepted = false;
dvander@592
   778
	bool handled = false;
dvander@592
   779
faluco@593
   780
	pList = &m_msgIntercepts[m_CurId];
faluco@593
   781
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   782
	{
faluco@593
   783
		pInfo = (*iter);
faluco@593
   784
		pInfo->IsHooked = true;
skamonkey@3743
   785
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   786
		res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
skamonkey@3743
   787
#else
faluco@593
   788
		res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
skamonkey@3743
   789
#endif
faluco@593
   790
faluco@597
   791
		intercepted = true;
faluco@597
   792
faluco@593
   793
		switch (res)
dvander@592
   794
		{
faluco@593
   795
		case Pl_Stop:
faluco@593
   796
			{
faluco@593
   797
				if (pInfo->KillMe)
faluco@593
   798
				{
faluco@593
   799
					pList->erase(iter);
faluco@593
   800
					m_FreeListeners.push(pInfo);
faluco@593
   801
					_DecRefCounter();
faluco@593
   802
					goto supercede;
faluco@593
   803
				}
faluco@593
   804
				pInfo->IsHooked = false;
faluco@593
   805
				goto supercede;
faluco@593
   806
			}
faluco@593
   807
		case Pl_Handled:
faluco@593
   808
			{
faluco@593
   809
				handled = true;
faluco@593
   810
				if (pInfo->KillMe)
faluco@593
   811
				{
faluco@593
   812
					iter = pList->erase(iter);
faluco@593
   813
					m_FreeListeners.push(pInfo);
faluco@593
   814
					_DecRefCounter();
faluco@593
   815
					continue;
faluco@593
   816
				}
faluco@593
   817
				break;
faluco@593
   818
			}
faluco@593
   819
		default:
faluco@593
   820
			{
faluco@593
   821
				if (pInfo->KillMe)
faluco@593
   822
				{
faluco@593
   823
					iter = pList->erase(iter);
faluco@593
   824
					m_FreeListeners.push(pInfo);
faluco@593
   825
					_DecRefCounter();
faluco@593
   826
					continue;
faluco@593
   827
				}
faluco@597
   828
				break;
faluco@593
   829
			}
dvander@592
   830
		}
faluco@593
   831
		pInfo->IsHooked = false;
faluco@593
   832
		iter++;
dvander@592
   833
	}
dvander@592
   834
dvander@2734
   835
	if (!handled && intercepted)
dvander@592
   836
	{
skamonkey@3743
   837
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   838
		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
skamonkey@3743
   839
		delete m_InterceptBuffer;
skamonkey@3743
   840
		m_InterceptBuffer = NULL;
skamonkey@3743
   841
#else
faluco@593
   842
		bf_write *engine_bfw;
ds@3099
   843
#if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   844
		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId));
ds@2400
   845
#else
dvander@592
   846
		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
ds@2400
   847
#endif
dvander@592
   848
		m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
dvander@592
   849
		engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
dvander@592
   850
		ENGINE_CALL(MessageEnd)();
skamonkey@3743
   851
#endif // SE_CSGO
dvander@592
   852
	}
dvander@592
   853
faluco@593
   854
	pList = &m_msgHooks[m_CurId];
faluco@593
   855
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   856
	{
faluco@593
   857
		pInfo = (*iter);
faluco@593
   858
		pInfo->IsHooked = true;
faluco@593
   859
		pInfo->Callback->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
faluco@593
   860
faluco@593
   861
		if (pInfo->KillMe)
faluco@593
   862
		{
faluco@593
   863
			iter = pList->erase(iter);
faluco@593
   864
			m_FreeListeners.push(pInfo);
faluco@593
   865
			_DecRefCounter();
faluco@593
   866
			continue;
faluco@593
   867
		}
faluco@593
   868
faluco@594
   869
		pInfo->IsHooked = false;
faluco@593
   870
		iter++;
dvander@592
   871
	}
dvander@592
   872
skamonkey@3743
   873
	UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
dvander@592
   874
supercede:
faluco@597
   875
	m_BlockEndPost = true;
skamonkey@3743
   876
	UM_RETURN_META(MRES_SUPERCEDE);
dvander@592
   877
}