core/UserMessages.cpp
author David Anderson <dvander@alliedmods.net>
Thu Mar 15 04:45:33 2007 +0000 (2007-03-15)
changeset 617 dc7671b320e4
parent 616 d5b1dcf38c07
child 641 ce1f369ba889
permissions -rw-r--r--
fixed two spelling mistakes
dvander@592
     1
/**
dvander@592
     2
* vim: set ts=4 :
dvander@592
     3
* ===============================================================
dvander@592
     4
* SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
dvander@592
     5
* ===============================================================
dvander@592
     6
*
dvander@592
     7
* This file is not open source and may not be copied without explicit
dvander@592
     8
* written permission of AlliedModders LLC.  This file may not be redistributed 
dvander@592
     9
* in whole or significant part.
dvander@592
    10
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
dvander@592
    11
*
dvander@592
    12
* Version: $Id$
dvander@592
    13
*/
dvander@592
    14
dvander@592
    15
#include "UserMessages.h"
dvander@592
    16
dvander@616
    17
UserMessages g_UserMsgs;
dvander@592
    18
dvander@592
    19
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
dvander@592
    20
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
dvander@592
    21
dvander@592
    22
//:TODO: USE NEW MM IFACE TO SEARCH FOR MESSAGE NAMES ETC! faluco--> i'll do this when i have some spare time
dvander@592
    23
dvander@616
    24
UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500)
dvander@592
    25
{
dvander@592
    26
	m_Names = sm_trie_create();
dvander@592
    27
	m_HookCount = 0;
dvander@592
    28
	m_InExec = false;
dvander@592
    29
	m_InHook = false;
dvander@592
    30
	m_CurFlags = 0;
dvander@592
    31
	m_CurId = INVALID_MESSAGE_ID;
dvander@592
    32
}
dvander@592
    33
dvander@616
    34
UserMessages::~UserMessages()
dvander@592
    35
{
dvander@592
    36
	sm_trie_destroy(m_Names);
dvander@592
    37
}
dvander@592
    38
dvander@616
    39
void UserMessages::OnSourceModAllInitialized()
dvander@592
    40
{
dvander@592
    41
	g_ShareSys.AddInterface(NULL, this);
dvander@592
    42
}
dvander@592
    43
dvander@616
    44
void UserMessages::OnSourceModAllShutdown()
dvander@592
    45
{
dvander@592
    46
	if (m_HookCount)
dvander@592
    47
	{
dvander@616
    48
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
dvander@616
    49
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
dvander@616
    50
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
dvander@616
    51
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
dvander@592
    52
	}
dvander@592
    53
	m_HookCount = 0;
dvander@592
    54
}
dvander@592
    55
dvander@616
    56
int UserMessages::GetMessageIndex(const char *msg)
dvander@592
    57
{
dvander@592
    58
	int msgid;
dvander@592
    59
	if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
dvander@592
    60
	{
dvander@592
    61
		char buf[255];
dvander@592
    62
		int dummy;
dvander@592
    63
		msgid = 0;
dvander@592
    64
dvander@592
    65
		while (gamedll->GetUserMessageInfo(msgid, buf, sizeof(buf), dummy))
dvander@592
    66
		{
dvander@592
    67
			if (strcmp(msg, buf) == 0)
dvander@592
    68
			{
dvander@592
    69
				sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
dvander@592
    70
				return msgid;
dvander@592
    71
			}
dvander@592
    72
			msgid++;
dvander@592
    73
		}
dvander@592
    74
dvander@592
    75
		return INVALID_MESSAGE_ID;
dvander@592
    76
	}
dvander@592
    77
dvander@592
    78
	return msgid;
dvander@592
    79
}
dvander@592
    80
dvander@616
    81
bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlen) const
dvander@592
    82
{
dvander@592
    83
	int dummy;
dvander@592
    84
dvander@592
    85
	return gamedll->GetUserMessageInfo(msgid, buffer, maxlen, dummy);
dvander@592
    86
}
dvander@592
    87
dvander@616
    88
bf_write *UserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags)
dvander@592
    89
{
dvander@592
    90
	bf_write *buffer;
faluco@593
    91
faluco@593
    92
	if (m_InExec || m_InHook)
dvander@592
    93
	{
dvander@592
    94
		return NULL;
dvander@592
    95
	}
dvander@592
    96
	if (msg_id < 0 || msg_id >= 255)
dvander@592
    97
	{
dvander@592
    98
		return NULL;
dvander@592
    99
	}
dvander@592
   100
faluco@593
   101
	m_CellRecFilter.Initialize(players, playersNum);
dvander@592
   102
dvander@592
   103
	m_CurFlags = flags;
dvander@592
   104
	if (m_CurFlags & USERMSG_INITMSG)
dvander@592
   105
	{
faluco@593
   106
		m_CellRecFilter.SetToInit(true);
dvander@592
   107
	}
dvander@592
   108
	if (m_CurFlags & USERMSG_RELIABLE)
dvander@592
   109
	{
faluco@593
   110
		m_CellRecFilter.SetToReliable(true);
dvander@592
   111
	}
dvander@592
   112
dvander@592
   113
	m_InExec = true;
dvander@592
   114
dvander@592
   115
	if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
dvander@592
   116
	{
dvander@592
   117
		buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
dvander@592
   118
	} else {
dvander@592
   119
		buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
dvander@592
   120
	}
dvander@592
   121
dvander@592
   122
	return buffer;
dvander@592
   123
}
dvander@592
   124
dvander@616
   125
bool UserMessages::EndMessage()
dvander@592
   126
{
dvander@592
   127
	if (!m_InExec)
dvander@592
   128
	{
dvander@592
   129
		return false;
dvander@592
   130
	}
dvander@592
   131
dvander@592
   132
	if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
dvander@592
   133
	{
dvander@592
   134
		engine->MessageEnd();
dvander@592
   135
	} else {
dvander@592
   136
		ENGINE_CALL(MessageEnd)();
dvander@592
   137
	}
dvander@592
   138
dvander@592
   139
	m_InExec = false;
dvander@592
   140
	m_CurFlags = 0;
faluco@593
   141
	m_CellRecFilter.Reset();
dvander@592
   142
dvander@592
   143
	return true;
dvander@592
   144
}
dvander@592
   145
dvander@616
   146
bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
dvander@592
   147
{
dvander@592
   148
	if (msg_id < 0 || msg_id >= 255)
dvander@592
   149
	{
dvander@592
   150
		return false;
dvander@592
   151
	}
dvander@592
   152
faluco@593
   153
	ListenerInfo *pInfo;
faluco@593
   154
	if (m_FreeListeners.empty())
faluco@593
   155
	{
faluco@593
   156
		pInfo = new ListenerInfo;
faluco@593
   157
	} else {
faluco@593
   158
		pInfo = m_FreeListeners.front();
faluco@593
   159
		m_FreeListeners.pop();
faluco@593
   160
	}
faluco@593
   161
faluco@593
   162
	pInfo->Callback = pListener;
faluco@593
   163
	pInfo->IsHooked = false;
faluco@593
   164
	pInfo->KillMe = false;
faluco@593
   165
dvander@592
   166
	if (!m_HookCount++)
dvander@592
   167
	{
dvander@616
   168
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
dvander@616
   169
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
dvander@616
   170
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
dvander@616
   171
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
dvander@592
   172
	}
dvander@592
   173
dvander@592
   174
	if (intercept)
dvander@592
   175
	{
faluco@593
   176
		m_msgIntercepts[msg_id].push_back(pInfo);
dvander@592
   177
	} else {
faluco@593
   178
		m_msgHooks[msg_id].push_back(pInfo);
dvander@592
   179
	}
dvander@592
   180
dvander@592
   181
	return true;
dvander@592
   182
}
dvander@592
   183
dvander@616
   184
bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
faluco@593
   185
{	
faluco@593
   186
	MsgList *pList;
dvander@592
   187
	MsgIter iter;
faluco@593
   188
	ListenerInfo *pInfo;
dvander@592
   189
	bool deleted = false;
dvander@592
   190
dvander@592
   191
	if (msg_id < 0 || msg_id >= 255)
dvander@592
   192
	{
dvander@592
   193
		return false;
dvander@592
   194
	}
dvander@592
   195
faluco@593
   196
	pList = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
faluco@593
   197
	for (iter=pList->begin(); iter!=pList->end(); iter++)
dvander@592
   198
	{
faluco@593
   199
		pInfo = (*iter);
faluco@593
   200
		if (pInfo->Callback == pListener)
dvander@592
   201
		{
faluco@593
   202
			if (pInfo->IsHooked)
faluco@593
   203
			{
faluco@593
   204
				pInfo->KillMe = true;
faluco@593
   205
				return true;
faluco@593
   206
			}
faluco@593
   207
			pList->erase(iter);
dvander@592
   208
			deleted = true;
dvander@592
   209
			break;
dvander@592
   210
		}
dvander@592
   211
	}
dvander@592
   212
faluco@593
   213
	if (deleted)
faluco@593
   214
	{
faluco@593
   215
		_DecRefCounter();
faluco@593
   216
	}
faluco@593
   217
faluco@593
   218
	return deleted;
faluco@593
   219
}
faluco@593
   220
dvander@616
   221
void UserMessages::_DecRefCounter()
faluco@593
   222
{
faluco@593
   223
	if (--m_HookCount == 0)
dvander@592
   224
	{
dvander@616
   225
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
dvander@616
   226
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
dvander@616
   227
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
dvander@616
   228
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
dvander@592
   229
	}
dvander@592
   230
}
dvander@592
   231
dvander@616
   232
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
dvander@592
   233
{
dvander@592
   234
	bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
dvander@592
   235
	bool is_hook_empty = m_msgHooks[msg_type].empty();
dvander@592
   236
faluco@593
   237
	if ((is_intercept_empty && is_hook_empty)
faluco@593
   238
		|| (m_InExec && !(m_CurFlags & USERMSG_PASSTHRU_ALL)))
dvander@592
   239
	{
dvander@592
   240
		m_InHook = false;
dvander@592
   241
		RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   242
	}
dvander@592
   243
dvander@592
   244
	m_CurId = msg_type;
dvander@592
   245
	m_CurRecFilter = filter;
dvander@592
   246
	m_InHook = true;
faluco@597
   247
	m_BlockEndPost = false;
dvander@592
   248
dvander@592
   249
	if (!is_intercept_empty)
dvander@592
   250
	{
faluco@593
   251
		m_InterceptBuffer.Reset();
dvander@592
   252
		RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
dvander@592
   253
	}
dvander@592
   254
dvander@592
   255
	RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   256
}
dvander@592
   257
dvander@616
   258
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
dvander@592
   259
{
dvander@592
   260
	if (!m_InHook)
dvander@592
   261
	{
dvander@592
   262
		RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   263
	}
dvander@592
   264
dvander@592
   265
	m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
dvander@592
   266
dvander@592
   267
	RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   268
}
dvander@592
   269
dvander@616
   270
void UserMessages::OnMessageEnd_Post()
dvander@592
   271
{
faluco@597
   272
	if (!m_InHook || m_BlockEndPost)
dvander@592
   273
	{
dvander@592
   274
		RETURN_META(MRES_IGNORED);
dvander@592
   275
	}
dvander@592
   276
faluco@593
   277
	MsgList *pList;
dvander@592
   278
	MsgIter iter;
faluco@593
   279
	ListenerInfo *pInfo;
faluco@593
   280
faluco@593
   281
	pList = &m_msgIntercepts[m_CurId];
faluco@593
   282
	for (iter=pList->begin(); iter!=pList->end(); )
faluco@593
   283
	{
faluco@593
   284
		pInfo = (*iter);
faluco@593
   285
		pInfo->IsHooked = true;
faluco@593
   286
		pInfo->Callback->OnUserMessageSent(m_CurId);
dvander@592
   287
faluco@593
   288
		if (pInfo->KillMe)
faluco@593
   289
		{
faluco@593
   290
			iter = pList->erase(iter);
faluco@593
   291
			m_FreeListeners.push(pInfo);
faluco@593
   292
			_DecRefCounter();
faluco@593
   293
			continue;
faluco@593
   294
		}
faluco@593
   295
faluco@593
   296
		pInfo->IsHooked = false;
faluco@593
   297
		iter++;
dvander@592
   298
	}
dvander@592
   299
faluco@593
   300
	pList = &m_msgHooks[m_CurId];
faluco@594
   301
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   302
	{
faluco@593
   303
		pInfo = (*iter);
faluco@594
   304
		pInfo->IsHooked = true;
faluco@593
   305
		pInfo->Callback->OnUserMessageSent(m_CurId);
faluco@593
   306
faluco@593
   307
		if (pInfo->KillMe)
faluco@593
   308
		{
faluco@593
   309
			iter = pList->erase(iter);
faluco@593
   310
			m_FreeListeners.push(pInfo);
faluco@593
   311
			_DecRefCounter();
faluco@593
   312
			continue;
faluco@593
   313
		}
faluco@593
   314
faluco@593
   315
		pInfo->IsHooked = false;
faluco@593
   316
		iter++;
dvander@592
   317
	}
faluco@593
   318
faluco@593
   319
	m_InHook = false;
dvander@592
   320
}
dvander@592
   321
dvander@616
   322
void UserMessages::OnMessageEnd_Pre()
dvander@592
   323
{
dvander@592
   324
	if (!m_InHook)
dvander@592
   325
	{
dvander@592
   326
		RETURN_META(MRES_IGNORED);
dvander@592
   327
	}
dvander@592
   328
faluco@593
   329
	MsgList *pList;
dvander@592
   330
	MsgIter iter;
faluco@593
   331
	ListenerInfo *pInfo;
faluco@593
   332
dvander@592
   333
	ResultType res;
dvander@592
   334
	bool intercepted = false;
dvander@592
   335
	bool handled = false;
dvander@592
   336
faluco@593
   337
	pList = &m_msgIntercepts[m_CurId];
faluco@593
   338
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   339
	{
faluco@593
   340
		pInfo = (*iter);
faluco@593
   341
		pInfo->IsHooked = true;
faluco@593
   342
		res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
faluco@593
   343
faluco@597
   344
		intercepted = true;
faluco@597
   345
faluco@593
   346
		switch (res)
dvander@592
   347
		{
faluco@593
   348
		case Pl_Stop:
faluco@593
   349
			{
faluco@593
   350
				if (pInfo->KillMe)
faluco@593
   351
				{
faluco@593
   352
					pList->erase(iter);
faluco@593
   353
					m_FreeListeners.push(pInfo);
faluco@593
   354
					_DecRefCounter();
faluco@593
   355
					goto supercede;
faluco@593
   356
				}
faluco@593
   357
				pInfo->IsHooked = false;
faluco@593
   358
				goto supercede;
faluco@593
   359
			}
faluco@593
   360
		case Pl_Handled:
faluco@593
   361
			{
faluco@593
   362
				handled = true;
faluco@593
   363
				if (pInfo->KillMe)
faluco@593
   364
				{
faluco@593
   365
					iter = pList->erase(iter);
faluco@593
   366
					m_FreeListeners.push(pInfo);
faluco@593
   367
					_DecRefCounter();
faluco@593
   368
					continue;
faluco@593
   369
				}
faluco@593
   370
				break;
faluco@593
   371
			}
faluco@593
   372
		default:
faluco@593
   373
			{
faluco@593
   374
				if (pInfo->KillMe)
faluco@593
   375
				{
faluco@593
   376
					iter = pList->erase(iter);
faluco@593
   377
					m_FreeListeners.push(pInfo);
faluco@593
   378
					_DecRefCounter();
faluco@593
   379
					continue;
faluco@593
   380
				}
faluco@597
   381
				break;
faluco@593
   382
			}
dvander@592
   383
		}
faluco@593
   384
		pInfo->IsHooked = false;
faluco@593
   385
		iter++;
dvander@592
   386
	}
dvander@592
   387
dvander@592
   388
	if (handled)
dvander@592
   389
	{
dvander@592
   390
		goto supercede;
dvander@592
   391
	}
dvander@592
   392
dvander@592
   393
	if (intercepted)
dvander@592
   394
	{
faluco@593
   395
		bf_write *engine_bfw;
faluco@593
   396
dvander@592
   397
		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
dvander@592
   398
		m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
dvander@592
   399
		engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
dvander@592
   400
		ENGINE_CALL(MessageEnd)();
dvander@592
   401
	}
dvander@592
   402
faluco@593
   403
	pList = &m_msgHooks[m_CurId];
faluco@593
   404
	for (iter=pList->begin(); iter!=pList->end(); )
dvander@592
   405
	{
faluco@593
   406
		pInfo = (*iter);
faluco@593
   407
		pInfo->IsHooked = true;
faluco@593
   408
		pInfo->Callback->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
faluco@593
   409
faluco@593
   410
		if (pInfo->KillMe)
faluco@593
   411
		{
faluco@593
   412
			iter = pList->erase(iter);
faluco@593
   413
			m_FreeListeners.push(pInfo);
faluco@593
   414
			_DecRefCounter();
faluco@593
   415
			continue;
faluco@593
   416
		}
faluco@593
   417
faluco@594
   418
		pInfo->IsHooked = false;
faluco@593
   419
		iter++;
dvander@592
   420
	}
dvander@592
   421
faluco@597
   422
	RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
dvander@592
   423
supercede:
faluco@593
   424
	m_InHook = false;
faluco@597
   425
	m_BlockEndPost = true;
dvander@592
   426
	RETURN_META(MRES_SUPERCEDE);
dvander@592
   427
}