core/UserMessages.cpp
author David Anderson <dvander@alliedmods.net>
Sat Mar 10 21:26:04 2007 +0000 (2007-03-10)
changeset 592 c2a2c38f1331
child 593 507e74843261
permissions -rw-r--r--
part 2 of singleton renaming
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@592
    17
CUserMessages 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@592
    24
CUserMessages::CUserMessages() : 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@592
    34
CUserMessages::~CUserMessages()
dvander@592
    35
{
dvander@592
    36
	sm_trie_destroy(m_Names);
dvander@592
    37
}
dvander@592
    38
dvander@592
    39
void CUserMessages::OnSourceModAllInitialized()
dvander@592
    40
{
dvander@592
    41
	g_ShareSys.AddInterface(NULL, this);
dvander@592
    42
}
dvander@592
    43
dvander@592
    44
void CUserMessages::OnSourceModAllShutdown()
dvander@592
    45
{
dvander@592
    46
	if (m_HookCount)
dvander@592
    47
	{
dvander@592
    48
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
dvander@592
    49
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
dvander@592
    50
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
dvander@592
    51
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
dvander@592
    52
	}
dvander@592
    53
	m_HookCount = 0;
dvander@592
    54
}
dvander@592
    55
dvander@592
    56
int CUserMessages::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@592
    81
bool CUserMessages::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@592
    88
bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags)
dvander@592
    89
{
dvander@592
    90
	bf_write *buffer;
dvander@592
    91
	
dvander@592
    92
	if (m_InExec)
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
dvander@592
   101
	m_CellRecFilter.SetRecipientPtr(players, playersNum);
dvander@592
   102
dvander@592
   103
	m_CurFlags = flags;
dvander@592
   104
	if (m_CurFlags & USERMSG_INITMSG)
dvander@592
   105
	{
dvander@592
   106
		m_CellRecFilter.SetInitMessage(true);
dvander@592
   107
	}
dvander@592
   108
	if (m_CurFlags & USERMSG_RELIABLE)
dvander@592
   109
	{
dvander@592
   110
		m_CellRecFilter.SetReliable(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@592
   125
bool CUserMessages::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;
dvander@592
   141
	m_CellRecFilter.ResetFilter();
dvander@592
   142
dvander@592
   143
	return true;
dvander@592
   144
}
dvander@592
   145
dvander@592
   146
bool CUserMessages::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
dvander@592
   153
	if (!m_HookCount++)
dvander@592
   154
	{
dvander@592
   155
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
dvander@592
   156
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
dvander@592
   157
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
dvander@592
   158
		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
dvander@592
   159
	}
dvander@592
   160
dvander@592
   161
	if (intercept)
dvander@592
   162
	{
dvander@592
   163
		m_msgIntercepts[msg_id].push_back(pListener);
dvander@592
   164
	} else {
dvander@592
   165
		m_msgHooks[msg_id].push_back(pListener);
dvander@592
   166
	}
dvander@592
   167
dvander@592
   168
	return true;
dvander@592
   169
}
dvander@592
   170
dvander@592
   171
bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
dvander@592
   172
{
dvander@592
   173
	//:TODO: restrict user from unhooking stuff during a message hook to avoid iterator mess
dvander@592
   174
	List<IUserMessageListener *> *lst;
dvander@592
   175
	IUserMessageListener *listener;
dvander@592
   176
	MsgIter iter;
dvander@592
   177
	bool deleted = false;
dvander@592
   178
dvander@592
   179
	if (msg_id < 0 || msg_id >= 255)
dvander@592
   180
	{
dvander@592
   181
		return false;
dvander@592
   182
	}
dvander@592
   183
dvander@592
   184
	lst = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
dvander@592
   185
	for (iter=lst->begin(); iter!=lst->end(); iter++)
dvander@592
   186
	{
dvander@592
   187
		listener = (*iter);
dvander@592
   188
		if (listener == pListener)
dvander@592
   189
		{
dvander@592
   190
			lst->erase(iter);
dvander@592
   191
			deleted = true;
dvander@592
   192
			break;
dvander@592
   193
		}
dvander@592
   194
	}
dvander@592
   195
dvander@592
   196
	if (deleted && !(--m_HookCount))
dvander@592
   197
	{
dvander@592
   198
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
dvander@592
   199
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
dvander@592
   200
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
dvander@592
   201
		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
dvander@592
   202
	}
dvander@592
   203
dvander@592
   204
	return (deleted) ? true : false;
dvander@592
   205
}
dvander@592
   206
dvander@592
   207
bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
dvander@592
   208
{
dvander@592
   209
	bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
dvander@592
   210
	bool is_hook_empty = m_msgHooks[msg_type].empty();
dvander@592
   211
dvander@592
   212
	if (is_intercept_empty && is_hook_empty)
dvander@592
   213
	{
dvander@592
   214
		m_InHook = false;
dvander@592
   215
		RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   216
	}
dvander@592
   217
dvander@592
   218
	if ((m_InExec) && !(m_CurFlags & USERMSG_PASSTHRU_ALL))
dvander@592
   219
	{
dvander@592
   220
		m_InHook = false;
dvander@592
   221
		RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   222
	}
dvander@592
   223
dvander@592
   224
	m_CurId = msg_type;
dvander@592
   225
	m_CurRecFilter = filter;
dvander@592
   226
	m_InterceptBuffer.Reset();
dvander@592
   227
	m_InHook = true;
dvander@592
   228
dvander@592
   229
	if (!is_intercept_empty)
dvander@592
   230
	{
dvander@592
   231
		RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
dvander@592
   232
	}
dvander@592
   233
dvander@592
   234
	RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   235
}
dvander@592
   236
dvander@592
   237
bf_write *CUserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
dvander@592
   238
{
dvander@592
   239
	if (!m_InHook)
dvander@592
   240
	{
dvander@592
   241
		RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   242
	}
dvander@592
   243
dvander@592
   244
	m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
dvander@592
   245
dvander@592
   246
	RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592
   247
}
dvander@592
   248
dvander@592
   249
void CUserMessages::OnMessageEnd_Post()
dvander@592
   250
{
dvander@592
   251
	if (!m_InHook || (META_RESULT_STATUS == MRES_SUPERCEDE))
dvander@592
   252
	{
dvander@592
   253
		RETURN_META(MRES_IGNORED);
dvander@592
   254
	}
dvander@592
   255
dvander@592
   256
	List<IUserMessageListener *> *lst;
dvander@592
   257
	IUserMessageListener *listener;
dvander@592
   258
	MsgIter iter;
dvander@592
   259
dvander@592
   260
	lst = &m_msgIntercepts[m_CurId];
dvander@592
   261
	for (iter=lst->begin(); iter!=lst->end(); iter++)
dvander@592
   262
	{
dvander@592
   263
		listener = (*iter);
dvander@592
   264
		listener->OnUserMessageSent(m_CurId);
dvander@592
   265
	}
dvander@592
   266
dvander@592
   267
	lst = &m_msgHooks[m_CurId];
dvander@592
   268
	for (iter=lst->begin(); iter!=lst->end(); iter++)
dvander@592
   269
	{
dvander@592
   270
		listener = (*iter);
dvander@592
   271
		listener->OnUserMessageSent(m_CurId);
dvander@592
   272
	}
dvander@592
   273
}
dvander@592
   274
dvander@592
   275
void CUserMessages::OnMessageEnd_Pre()
dvander@592
   276
{
dvander@592
   277
	if (!m_InHook)
dvander@592
   278
	{
dvander@592
   279
		RETURN_META(MRES_IGNORED);
dvander@592
   280
	}
dvander@592
   281
dvander@592
   282
	List<IUserMessageListener *> *lst;
dvander@592
   283
	IUserMessageListener *listener;
dvander@592
   284
	bf_write *engine_bfw;
dvander@592
   285
	MsgIter iter;
dvander@592
   286
	ResultType res;
dvander@592
   287
	bool intercepted = false;
dvander@592
   288
	bool handled = false;
dvander@592
   289
dvander@592
   290
	lst = &m_msgIntercepts[m_CurId];
dvander@592
   291
	for (iter=lst->begin(); iter!=lst->end(); iter++)
dvander@592
   292
	{
dvander@592
   293
		listener = (*iter);
dvander@592
   294
		res = listener->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
dvander@592
   295
		if (res == Pl_Stop)
dvander@592
   296
		{
dvander@592
   297
			goto supercede;
dvander@592
   298
		} else if (res == Pl_Handled) {
dvander@592
   299
			handled = true;
dvander@592
   300
		}
dvander@592
   301
		intercepted = true;
dvander@592
   302
	}
dvander@592
   303
dvander@592
   304
	if (handled)
dvander@592
   305
	{
dvander@592
   306
		goto supercede;
dvander@592
   307
	}
dvander@592
   308
dvander@592
   309
	if (intercepted)
dvander@592
   310
	{
dvander@592
   311
		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
dvander@592
   312
		m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
dvander@592
   313
		engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
dvander@592
   314
		ENGINE_CALL(MessageEnd)();
dvander@592
   315
		goto supercede;
dvander@592
   316
	}
dvander@592
   317
dvander@592
   318
	lst = &m_msgHooks[m_CurId];
dvander@592
   319
	for (iter=lst->begin(); iter!=lst->end(); iter++)
dvander@592
   320
	{
dvander@592
   321
		listener = (*iter);
dvander@592
   322
		listener->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
dvander@592
   323
	}
dvander@592
   324
dvander@592
   325
	RETURN_META(MRES_IGNORED);
dvander@592
   326
supercede:
dvander@592
   327
	RETURN_META(MRES_SUPERCEDE);
dvander@592
   328
}