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 "UserMessages.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::OnSourceModAllInitialized()
41 g_ShareSys.AddInterface(NULL, this);
44 void CUserMessages::OnSourceModAllShutdown()
48 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
49 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
50 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
51 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
56 int CUserMessages::GetMessageIndex(const char *msg)
59 if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
65 while (gamedll->GetUserMessageInfo(msgid, buf, sizeof(buf), dummy))
67 if (strcmp(msg, buf) == 0)
69 sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
75 return INVALID_MESSAGE_ID;
81 bool CUserMessages::GetMessageName(int msgid, char *buffer, size_t maxlen) const
85 return gamedll->GetUserMessageInfo(msgid, buffer, maxlen, dummy);
88 bf_write *CUserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags)
96 if (msg_id < 0 || msg_id >= 255)
101 m_CellRecFilter.SetRecipientPtr(players, playersNum);
104 if (m_CurFlags & USERMSG_INITMSG)
106 m_CellRecFilter.SetInitMessage(true);
108 if (m_CurFlags & USERMSG_RELIABLE)
110 m_CellRecFilter.SetReliable(true);
115 if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
117 buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
119 buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
125 bool CUserMessages::EndMessage()
132 if (m_CurFlags & (USERMSG_PASSTHRU_ALL|USERMSG_PASSTHRU))
134 engine->MessageEnd();
136 ENGINE_CALL(MessageEnd)();
141 m_CellRecFilter.ResetFilter();
146 bool CUserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
148 if (msg_id < 0 || msg_id >= 255)
155 SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
156 SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
157 SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
158 SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
163 m_msgIntercepts[msg_id].push_back(pListener);
165 m_msgHooks[msg_id].push_back(pListener);
171 bool CUserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
173 //:TODO: restrict user from unhooking stuff during a message hook to avoid iterator mess
174 List<IUserMessageListener *> *lst;
175 IUserMessageListener *listener;
177 bool deleted = false;
179 if (msg_id < 0 || msg_id >= 255)
184 lst = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
185 for (iter=lst->begin(); iter!=lst->end(); iter++)
188 if (listener == pListener)
196 if (deleted && !(--m_HookCount))
198 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Pre, false);
199 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &CUserMessages::OnStartMessage_Post, true);
200 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Pre, false);
201 SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &CUserMessages::OnMessageEnd_Post, true);
204 return (deleted) ? true : false;
207 bf_write *CUserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
209 bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
210 bool is_hook_empty = m_msgHooks[msg_type].empty();
212 if (is_intercept_empty && is_hook_empty)
215 RETURN_META_VALUE(MRES_IGNORED, NULL);
218 if ((m_InExec) && !(m_CurFlags & USERMSG_PASSTHRU_ALL))
221 RETURN_META_VALUE(MRES_IGNORED, NULL);
225 m_CurRecFilter = filter;
226 m_InterceptBuffer.Reset();
229 if (!is_intercept_empty)
231 RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
234 RETURN_META_VALUE(MRES_IGNORED, NULL);
237 bf_write *CUserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
241 RETURN_META_VALUE(MRES_IGNORED, NULL);
244 m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
246 RETURN_META_VALUE(MRES_IGNORED, NULL);
249 void CUserMessages::OnMessageEnd_Post()
251 if (!m_InHook || (META_RESULT_STATUS == MRES_SUPERCEDE))
253 RETURN_META(MRES_IGNORED);
256 List<IUserMessageListener *> *lst;
257 IUserMessageListener *listener;
260 lst = &m_msgIntercepts[m_CurId];
261 for (iter=lst->begin(); iter!=lst->end(); iter++)
264 listener->OnUserMessageSent(m_CurId);
267 lst = &m_msgHooks[m_CurId];
268 for (iter=lst->begin(); iter!=lst->end(); iter++)
271 listener->OnUserMessageSent(m_CurId);
275 void CUserMessages::OnMessageEnd_Pre()
279 RETURN_META(MRES_IGNORED);
282 List<IUserMessageListener *> *lst;
283 IUserMessageListener *listener;
284 bf_write *engine_bfw;
287 bool intercepted = false;
288 bool handled = false;
290 lst = &m_msgIntercepts[m_CurId];
291 for (iter=lst->begin(); iter!=lst->end(); iter++)
294 res = listener->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
298 } else if (res == Pl_Handled) {
311 engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
312 m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
313 engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
314 ENGINE_CALL(MessageEnd)();
318 lst = &m_msgHooks[m_CurId];
319 for (iter=lst->begin(); iter!=lst->end(); iter++)
322 listener->OnUserMessage(m_CurId, m_OrigBuffer, m_CurRecFilter);
325 RETURN_META(MRES_IGNORED);
327 RETURN_META(MRES_SUPERCEDE);