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