3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
15 #include "CUserMessages.h"
17 CUserMessages g_UserMsgs;
19 SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
20 SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
22 //:TODO: USE NEW MM IFACE TO SEARCH FOR MESSAGE NAMES ETC! faluco--> i'll do this when i have some spare time
24 CUserMessages::CUserMessages() : m_InterceptBuffer(m_pBase, 2500)
26 m_Names = sm_trie_create();
31 m_CurId = INVALID_MESSAGE_ID;
34 CUserMessages::~CUserMessages()
36 sm_trie_destroy(m_Names);
39 void CUserMessages::OnSourceModAllShutdown()
43 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
44 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
45 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
46 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
51 int CUserMessages::GetMessageIndex(const char *msg)
54 if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
60 while (gamedll->GetUserMessageInfo(msgid, buf, sizeof(buf), dummy))
62 if (strcmp(msg, buf) == 0)
64 sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
70 return INVALID_MESSAGE_ID;
76 bool CUserMessages::GetMessageName(int msgid, char *buffer, size_t maxlen) const
80 return gamedll->GetUserMessageInfo(msgid, buffer, maxlen, dummy);
83 bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags)
91 if (msg_id < 0 || msg_id >= 255)
96 m_CellRecFilter.SetRecipientPtr(players, playersNum);
99 if (m_CurFlags & USERMSG_INITMSG)
101 m_CellRecFilter.SetInitMessage(true);
103 if (m_CurFlags & USERMSG_RELIABLE)
105 m_CellRecFilter.SetReliable(true);
110 if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
112 buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
114 buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
120 bool CUserMessages::EndMessage()
127 if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
129 engine->MessageEnd();
131 ENGINE_CALL(MessageEnd)();
136 m_CellRecFilter.ResetFilter();
141 bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
143 if (msg_id < 0 || msg_id >= 255)
150 SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
151 SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
152 SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
153 SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
158 m_msgIntercepts[msg_id].push_back(pListener);
160 m_msgHooks[msg_id].push_back(pListener);
166 bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
168 //:TODO: restrict user from unhooking stuff during a message hook to avoid iterator mess
169 List<IUserMessageListener *> *lst;
170 IUserMessageListener *listener;
172 bool deleted = false;
174 if (msg_id < 0 || msg_id >= 255)
179 lst = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
180 for (iter=lst->begin(); iter!=lst->end(); iter++)
183 if (listener == pListener)
191 if (deleted && !(--m_HookCount))
193 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
194 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
195 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
196 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
199 return (deleted) ? true : false;
202 bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
204 bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
205 bool is_hook_empty = m_msgHooks[msg_type].empty();
207 if (is_intercept_empty && is_hook_empty)
210 RETURN_META_VALUE(MRES_IGNORED, NULL);
213 if ((m_InExec) && !(m_CurFlags & USERMSG_PASSTHRU_ALL))
216 RETURN_META_VALUE(MRES_IGNORED, NULL);
220 m_CurRecFilter = filter;
221 m_InterceptBuffer.Reset();
224 if (!is_intercept_empty)
226 RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
229 RETURN_META_VALUE(MRES_IGNORED, NULL);
232 bf_write *CUserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
236 RETURN_META_VALUE(MRES_IGNORED, NULL);
239 m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
241 RETURN_META_VALUE(MRES_IGNORED, NULL);
244 void CUserMessages::OnMessageEnd_Post()
246 if (!m_InHook || (META_RESULT_STATUS == MRES_SUPERCEDE))
248 RETURN_META(MRES_IGNORED);
251 List<IUserMessageListener *> *lst;
252 IUserMessageListener *listener;
255 lst = &m_msgIntercepts[m_CurId];
256 for (iter=lst->begin(); iter!=lst->end(); iter++)
259 listener->OnUserMessageSent(m_CurId);
262 lst = &m_msgHooks[m_CurId];
263 for (iter=lst->begin(); iter!=lst->end(); iter++)
266 listener->OnUserMessageSent(m_CurId);
270 void CUserMessages::OnMessageEnd_Pre()
274 RETURN_META(MRES_IGNORED);
277 List<IUserMessageListener *> *lst;
278 IUserMessageListener *listener;
279 bf_write *engine_bfw;
282 bool intercepted = false;
283 bool handled = false;
285 lst = &m_msgIntercepts[m_CurId];
286 for (iter=lst->begin(); iter!=lst->end(); iter++)
289 res = listener->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
293 } else if (res == Pl_Handled) {
306 engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
307 m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
308 engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
309 ENGINE_CALL(MessageEnd)();
313 lst = &m_msgHooks[m_CurId];
314 for (iter=lst->begin(); iter!=lst->end(); iter++)
317 listener->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
320 RETURN_META(MRES_IGNORED);
322 RETURN_META(MRES_SUPERCEDE);