core/UserMessages.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Sun Feb 10 23:11:04 2013 -0500 (2013-02-10)
changeset 3779 b269413e1258
parent 3778 4c210a5b3824
child 3786 cbbc2354ef1b
permissions -rw-r--r--
Fixed non-CS:GO builds.
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
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   497
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
skamonkey@3743
   498
{
skamonkey@3743
   499
	OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
skamonkey@3743
   500
	if (m_FakeMetaRes == MRES_SUPERCEDE)
skamonkey@3743
   501
	{
skamonkey@3778
   502
		int size = msg.ByteSize();
skamonkey@3778
   503
		uint8 *data = (uint8 *)stackalloc(size);
skamonkey@3778
   504
		msg.SerializePartialToArray(data, size);
skamonkey@3778
   505
		m_InterceptBuffer->ParseFromArray(data, size);
skamonkey@3743
   506
	}
skamonkey@3743
   507
	else
skamonkey@3743
   508
	{
skamonkey@3759
   509
		m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
skamonkey@3743
   510
		OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
skamonkey@3743
   511
	}
skamonkey@3743
   512
skamonkey@3743
   513
	OnMessageEnd_Pre();
skamonkey@3743
   514
	if (m_FakeMetaRes == MRES_SUPERCEDE)
skamonkey@3743
   515
		RETURN_META(MRES_SUPERCEDE);
skamonkey@3743
   516
skamonkey@3743
   517
	RETURN_META(MRES_IGNORED);
skamonkey@3743
   518
}
skamonkey@3743
   519
skamonkey@3743
   520
void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
skamonkey@3743
   521
{
skamonkey@3743
   522
	OnMessageEnd_Post();
skamonkey@3743
   523
	RETURN_META(MRES_IGNORED);
skamonkey@3743
   524
}
skamonkey@3743
   525
#endif
skamonkey@3743
   526
skamonkey@3743
   527
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   528
#define UM_RETURN_META_VALUE(res, val) \
skamonkey@3743
   529
	m_FakeMetaRes = res;               \
skamonkey@3743
   530
	return val;
skamonkey@3743
   531
skamonkey@3743
   532
#define UM_RETURN_META(res)            \
skamonkey@3743
   533
	m_FakeMetaRes = res;               \
skamonkey@3743
   534
	return;
skamonkey@3743
   535
#else
skamonkey@3743
   536
#define UM_RETURN_META_VALUE(res, val) \
skamonkey@3743
   537
	RETURN_META_VALUE(res, val)
skamonkey@3743
   538
skamonkey@3743
   539
#define UM_RETURN_META(res)            \
skamonkey@3743
   540
	RETURN_META(res)
skamonkey@3743
   541
#endif
skamonkey@3743
   542
skamonkey@3743
   543
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   544
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
skamonkey@3743
   545
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   546
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
ds@2400
   547
#else
dvander@616
   548
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
ds@2400
   549
#endif
dvander@592
   550
{
dvander@592
   551
	bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
dvander@592
   552
	bool is_hook_empty = m_msgHooks[msg_type].empty();
dvander@592
   553
faluco@593
   554
	if ((is_intercept_empty && is_hook_empty)
faluco@1250
   555
		|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
dvander@592
   556
	{
dvander@592
   557
		m_InHook = false;
skamonkey@3743
   558
		UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   559
	}
dvander@592
   560
dvander@592
   561
	m_CurId = msg_type;
dvander@592
   562
	m_CurRecFilter = filter;
dvander@592
   563
	m_InHook = true;
faluco@597
   564
	m_BlockEndPost = false;
dvander@592
   565
dvander@592
   566
	if (!is_intercept_empty)
dvander@592
   567
	{
skamonkey@3743
   568
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   569
		if (m_InterceptBuffer)
skamonkey@3743
   570
			delete m_InterceptBuffer;
skamonkey@3743
   571
		m_InterceptBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
skamonkey@3743
   572
		UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
skamonkey@3743
   573
#else
faluco@593
   574
		m_InterceptBuffer.Reset();
skamonkey@3743
   575
		UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
skamonkey@3743
   576
#endif
dvander@592
   577
	}
dvander@592
   578
skamonkey@3743
   579
	UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   580
}
dvander@592
   581
skamonkey@3743
   582
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   583
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
skamonkey@3743
   584
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   585
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
ds@2400
   586
#else
dvander@616
   587
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
ds@2400
   588
#endif
dvander@592
   589
{
dvander@592
   590
	if (!m_InHook)
dvander@592
   591
	{
skamonkey@3743
   592
		UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   593
	}
dvander@592
   594
skamonkey@3743
   595
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   596
	m_OrigBuffer = m_FakeEngineBuffer;
skamonkey@3743
   597
#else
dvander@592
   598
	m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
skamonkey@3743
   599
#endif
dvander@592
   600
skamonkey@3743
   601
	UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   602
}
dvander@592
   603
dvander@616
   604
void UserMessages::OnMessageEnd_Post()
dvander@592
   605
{
dvander@2636
   606
	if (!m_InHook)
dvander@592
   607
	{
skamonkey@3743
   608
		UM_RETURN_META(MRES_IGNORED);
dvander@592
   609
	}
dvander@592
   610
faluco@593
   611
	MsgList *pList;
dvander@592
   612
	MsgIter iter;
faluco@593
   613
	ListenerInfo *pInfo;
faluco@593
   614
pred@2577
   615
	m_InHook = false;
pred@2577
   616
faluco@593
   617
	pList = &m_msgIntercepts[m_CurId];
faluco@593
   618
	for (iter=pList->begin(); iter!=pList->end(); )
faluco@593
   619
	{
faluco@593
   620
		pInfo = (*iter);
dvander@2636
   621
		if (m_BlockEndPost && !pInfo->IsNew)
dvander@2636
   622
		{
dvander@2636
   623
			continue;
dvander@2636
   624
		}
faluco@593
   625
		pInfo->IsHooked = true;
faluco@593
   626
		pInfo->Callback->OnUserMessageSent(m_CurId);
dvander@2636
   627
		if (pInfo->IsNew)
dvander@2636
   628
		{
dvander@2636
   629
			pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
dvander@2636
   630
		}
dvander@592
   631
faluco@593
   632
		if (pInfo->KillMe)
faluco@593
   633
		{
faluco@593
   634
			iter = pList->erase(iter);
faluco@593
   635
			m_FreeListeners.push(pInfo);
faluco@593
   636
			_DecRefCounter();
faluco@593
   637
			continue;
faluco@593
   638
		}
faluco@593
   639
faluco@593
   640
		pInfo->IsHooked = false;
faluco@593
   641
		iter++;
dvander@592
   642
	}
dvander@592
   643
faluco@593
   644
	pList = &m_msgHooks[m_CurId];
faluco@594
   645
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   646
	{
faluco@593
   647
		pInfo = (*iter);
dvander@2636
   648
		if (m_BlockEndPost && !pInfo->IsNew)
dvander@2636
   649
		{
dvander@2636
   650
			continue;
dvander@2636
   651
		}
faluco@594
   652
		pInfo->IsHooked = true;
faluco@593
   653
		pInfo->Callback->OnUserMessageSent(m_CurId);
dvander@2636
   654
		if (pInfo->IsNew)
dvander@2636
   655
		{
dvander@2636
   656
			pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
dvander@2636
   657
		}
faluco@593
   658
faluco@593
   659
		if (pInfo->KillMe)
faluco@593
   660
		{
faluco@593
   661
			iter = pList->erase(iter);
faluco@593
   662
			m_FreeListeners.push(pInfo);
faluco@593
   663
			_DecRefCounter();
faluco@593
   664
			continue;
faluco@593
   665
		}
faluco@593
   666
faluco@593
   667
		pInfo->IsHooked = false;
faluco@593
   668
		iter++;
dvander@592
   669
	}
dvander@592
   670
}
dvander@592
   671
dvander@616
   672
void UserMessages::OnMessageEnd_Pre()
dvander@592
   673
{
dvander@592
   674
	if (!m_InHook)
dvander@592
   675
	{
skamonkey@3743
   676
		UM_RETURN_META(MRES_IGNORED);
dvander@592
   677
	}
dvander@592
   678
faluco@593
   679
	MsgList *pList;
dvander@592
   680
	MsgIter iter;
faluco@593
   681
	ListenerInfo *pInfo;
faluco@593
   682
dvander@592
   683
	ResultType res;
dvander@592
   684
	bool intercepted = false;
dvander@592
   685
	bool handled = false;
dvander@592
   686
faluco@593
   687
	pList = &m_msgIntercepts[m_CurId];
faluco@593
   688
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   689
	{
faluco@593
   690
		pInfo = (*iter);
faluco@593
   691
		pInfo->IsHooked = true;
skamonkey@3743
   692
#ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743
   693
		res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
skamonkey@3743
   694
#else
faluco@593
   695
		res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
skamonkey@3743
   696
#endif
faluco@593
   697
faluco@597
   698
		intercepted = true;
faluco@597
   699
faluco@593
   700
		switch (res)
dvander@592
   701
		{
faluco@593
   702
		case Pl_Stop:
faluco@593
   703
			{
faluco@593
   704
				if (pInfo->KillMe)
faluco@593
   705
				{
faluco@593
   706
					pList->erase(iter);
faluco@593
   707
					m_FreeListeners.push(pInfo);
faluco@593
   708
					_DecRefCounter();
faluco@593
   709
					goto supercede;
faluco@593
   710
				}
faluco@593
   711
				pInfo->IsHooked = false;
faluco@593
   712
				goto supercede;
faluco@593
   713
			}
faluco@593
   714
		case Pl_Handled:
faluco@593
   715
			{
faluco@593
   716
				handled = true;
faluco@593
   717
				if (pInfo->KillMe)
faluco@593
   718
				{
faluco@593
   719
					iter = pList->erase(iter);
faluco@593
   720
					m_FreeListeners.push(pInfo);
faluco@593
   721
					_DecRefCounter();
faluco@593
   722
					continue;
faluco@593
   723
				}
faluco@593
   724
				break;
faluco@593
   725
			}
faluco@593
   726
		default:
faluco@593
   727
			{
faluco@593
   728
				if (pInfo->KillMe)
faluco@593
   729
				{
faluco@593
   730
					iter = pList->erase(iter);
faluco@593
   731
					m_FreeListeners.push(pInfo);
faluco@593
   732
					_DecRefCounter();
faluco@593
   733
					continue;
faluco@593
   734
				}
faluco@597
   735
				break;
faluco@593
   736
			}
dvander@592
   737
		}
faluco@593
   738
		pInfo->IsHooked = false;
faluco@593
   739
		iter++;
dvander@592
   740
	}
dvander@592
   741
dvander@2734
   742
	if (!handled && intercepted)
dvander@592
   743
	{
skamonkey@3743
   744
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3743
   745
		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
skamonkey@3743
   746
		delete m_InterceptBuffer;
skamonkey@3743
   747
		m_InterceptBuffer = NULL;
skamonkey@3743
   748
#else
faluco@593
   749
		bf_write *engine_bfw;
ds@3099
   750
#if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400
   751
		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId));
ds@2400
   752
#else
dvander@592
   753
		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
ds@2400
   754
#endif
dvander@592
   755
		m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
dvander@592
   756
		engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
dvander@592
   757
		ENGINE_CALL(MessageEnd)();
skamonkey@3743
   758
#endif // SE_CSGO
dvander@592
   759
	}
dvander@592
   760
dvander@592
   761
	{
skamonkey@3779
   762
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3778
   763
		int size = m_OrigBuffer->ByteSize();
skamonkey@3778
   764
		uint8 *data = (uint8 *)stackalloc(size);
skamonkey@3778
   765
		m_OrigBuffer->SerializePartialToArray(data, size);
skamonkey@3778
   766
		protobuf::Message *pTempMsg = g_Cstrike15UsermessageHelpers.GetPrototype(m_CurId)->New();
skamonkey@3778
   767
		pTempMsg->ParseFromArray(data, size);
skamonkey@3779
   768
#else
skamonkey@3779
   769
		bf_write *pTempMsg = m_OrigBuffer;
skamonkey@3779
   770
#endif
faluco@593
   771
skamonkey@3778
   772
		pList = &m_msgHooks[m_CurId];
skamonkey@3778
   773
		for (iter=pList->begin(); iter!=pList->end(); )
faluco@593
   774
		{
skamonkey@3778
   775
			pInfo = (*iter);
skamonkey@3778
   776
			pInfo->IsHooked = true;
skamonkey@3778
   777
			pInfo->Callback->OnUserMessage(m_CurId, pTempMsg, m_CurRecFilter);
skamonkey@3778
   778
skamonkey@3778
   779
			if (pInfo->KillMe)
skamonkey@3778
   780
			{
skamonkey@3778
   781
				iter = pList->erase(iter);
skamonkey@3778
   782
				m_FreeListeners.push(pInfo);
skamonkey@3778
   783
				_DecRefCounter();
skamonkey@3778
   784
				continue;
skamonkey@3778
   785
			}
skamonkey@3778
   786
skamonkey@3778
   787
			pInfo->IsHooked = false;
skamonkey@3778
   788
			iter++;
faluco@593
   789
		}
faluco@593
   790
skamonkey@3779
   791
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3778
   792
		delete pTempMsg;
skamonkey@3779
   793
#endif
dvander@592
   794
	}
dvander@592
   795
skamonkey@3743
   796
	UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
dvander@592
   797
supercede:
faluco@597
   798
	m_BlockEndPost = true;
skamonkey@3743
   799
	UM_RETURN_META(MRES_SUPERCEDE);
dvander@592
   800
}