3 * =============================================================================
5 * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "UserMessages.h"
33 #include "sm_stringutil.h"
35 #if SOURCE_ENGINE == SE_DOTA
36 #include <dota_usermessage_helpers.h>
37 #elif SOURCE_ENGINE == SE_CSGO
38 #include <cstrike15_usermessage_helpers.h>
41 UserMessages g_UserMsgs;
43 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
44 SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
46 #if SOURCE_ENGINE >= SE_LEFT4DEAD
47 SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int, const char *);
49 SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
51 SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
54 UserMessages::UserMessages()
55 #ifndef USE_PROTOBUF_USERMESSAGES
56 : m_InterceptBuffer(m_pBase, 2500)
58 m_Names = sm_trie_create();
60 : m_InterceptBuffer(NULL)
67 m_CurId = INVALID_MESSAGE_ID;
70 UserMessages::~UserMessages()
72 #ifndef USE_PROTOBUF_USERMESSAGES
73 sm_trie_destroy(m_Names);
76 CStack<ListenerInfo *>::iterator iter;
77 for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
81 m_FreeListeners.popall();
84 void UserMessages::OnSourceModStartup(bool late)
86 #ifndef USE_PROTOBUF_USERMESSAGES
87 /* -1 means SourceMM was unable to get the user message list */
88 m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1);
92 void UserMessages::OnSourceModAllInitialized()
94 g_ShareSys.AddInterface(NULL, this);
97 void UserMessages::OnSourceModAllShutdown()
101 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
102 SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
103 SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
105 SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
106 SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
107 SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
108 SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
114 int UserMessages::GetMessageIndex(const char *msg)
116 #if SOURCE_ENGINE == SE_DOTA
117 // Can split this per engine and/or game later
118 return g_DotaUsermessageHelpers.GetIndex(msg);
119 #elif SOURCE_ENGINE == SE_CSGO
120 // Can split this per engine and/or game later
121 return g_Cstrike15UsermessageHelpers.GetIndex(msg);
125 if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
127 if (m_FallbackSearch)
133 while (gamedll->GetUserMessageInfo(msgid, msgbuf, sizeof(msgbuf), size))
135 if (strcmp(msgbuf, msg) == 0)
137 sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
144 msgid = g_SMAPI->FindUserMessage(msg);
146 if (msgid != INVALID_MESSAGE_ID)
148 sm_trie_insert(m_Names, msg, reinterpret_cast<void *>(msgid));
156 bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
158 #ifdef USE_PROTOBUF_USERMESSAGES
159 #if SOURCE_ENGINE == SE_DOTA
160 const char *pszName = g_DotaUsermessageHelpers.GetName(msgid);
161 #elif SOURCE_ENGINE == SE_CSGO
162 const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
167 strncopy(buffer, pszName, maxlength);
170 if (m_FallbackSearch)
173 return gamedll->GetUserMessageInfo(msgid, buffer, maxlength, size);
176 const char *msg = g_SMAPI->GetUserMessage(msgid);
180 strncopy(buffer, msg, maxlength);
188 bf_write *UserMessages::StartBitBufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
190 #ifdef USE_PROTOBUF_USERMESSAGES
195 if (m_InExec || m_InHook)
199 if (msg_id < 0 || msg_id >= 255)
204 m_CellRecFilter.Initialize(players, playersNum);
207 if (m_CurFlags & USERMSG_INITMSG)
209 m_CellRecFilter.SetToInit(true);
211 if (m_CurFlags & USERMSG_RELIABLE)
213 m_CellRecFilter.SetToReliable(true);
218 if (m_CurFlags & USERMSG_BLOCKHOOKS)
220 #if SOURCE_ENGINE >= SE_LEFT4DEAD
221 buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
223 buffer = ENGINE_CALL(UserMessageBegin)(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
226 #if SOURCE_ENGINE >= SE_LEFT4DEAD
227 buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
229 buffer = engine->UserMessageBegin(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id);
234 #endif // USE_PROTOBUF_USERMESSAGES
237 google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
239 #ifndef USE_PROTOBUF_USERMESSAGES
242 protobuf::Message *buffer;
244 if (m_InExec || m_InHook)
248 if (msg_id < 0 || msg_id >= 255)
254 m_CellRecFilter.Initialize(players, playersNum);
257 if (m_CurFlags & USERMSG_INITMSG)
259 m_CellRecFilter.SetToInit(true);
261 if (m_CurFlags & USERMSG_RELIABLE)
263 m_CellRecFilter.SetToReliable(true);
268 if (m_CurFlags & USERMSG_BLOCKHOOKS)
270 // direct message creation, return buffer "from engine". keep track
271 m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
272 buffer = m_FakeEngineBuffer;
274 char messageName[32];
275 if (!GetMessageName(msg_id, messageName, sizeof(messageName)))
281 protobuf::Message *msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
282 switch (m_FakeMetaRes)
286 m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
287 buffer = m_FakeEngineBuffer;
291 m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
298 OnStartMessage_Post(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
302 #endif // USE_PROTOBUF_USERMESSAGES
305 bool UserMessages::EndMessage()
312 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
313 if (m_CurFlags & USERMSG_BLOCKHOOKS)
315 ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
316 delete m_FakeEngineBuffer;
317 m_FakeEngineBuffer = NULL;
321 switch (m_FakeMetaRes)
326 engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
327 delete m_FakeEngineBuffer;
328 m_FakeEngineBuffer = NULL;
330 //case MRES_SUPERCEDE:
336 if (m_CurFlags & USERMSG_BLOCKHOOKS)
338 ENGINE_CALL(MessageEnd)();
340 engine->MessageEnd();
342 #endif // SE_CSGO || SE_DOTA
346 m_CellRecFilter.Reset();
351 UserMessageType UserMessages::GetUserMessageType() const
353 #ifdef USE_PROTOBUF_USERMESSAGES
360 bool UserMessages::HookUserMessage2(int msg_id,
361 IUserMessageListener *pListener,
364 #ifdef USE_PROTOBUF_USERMESSAGES
365 return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
367 return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
371 bool UserMessages::UnhookUserMessage2(int msg_id,
372 IUserMessageListener *pListener,
375 #ifdef USE_PROTOBUF_USERMESSAGES
376 return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
378 return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
382 bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
384 #ifdef USE_PROTOBUF_USERMESSAGES
385 return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
387 return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
391 bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
393 #ifdef USE_PROTOBUF_USERMESSAGES
394 return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
396 return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
400 #ifdef USE_PROTOBUF_USERMESSAGES
401 bool UserMessages::InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
403 bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
406 if (msg_id < 0 || msg_id >= 255)
412 if (m_FreeListeners.empty())
414 pInfo = new ListenerInfo;
416 pInfo = m_FreeListeners.front();
417 m_FreeListeners.pop();
420 pInfo->Callback = pListener;
421 pInfo->IsHooked = false;
422 pInfo->KillMe = false;
423 pInfo->IsNew = isNew;
427 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
428 SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
429 SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
431 SH_ADD_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
432 SH_ADD_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
433 SH_ADD_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
434 SH_ADD_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
440 m_msgIntercepts[msg_id].push_back(pInfo);
442 m_msgHooks[msg_id].push_back(pInfo);
448 #ifdef USE_PROTOBUF_USERMESSAGES
449 const protobuf::Message *GetMessagePrototype(int msg_type)
451 #if SOURCE_ENGINE == SE_DOTA
452 return g_DotaUsermessageHelpers.GetPrototype(msg_type);
453 #elif SOURCE_ENGINE == SE_CSGO
454 return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
459 #ifdef USE_PROTOBUF_USERMESSAGES
460 bool UserMessages::InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
462 bool UserMessages::InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
468 bool deleted = false;
470 if (msg_id < 0 || msg_id >= 255)
475 pList = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
476 for (iter=pList->begin(); iter!=pList->end(); iter++)
479 if (pInfo->Callback == pListener && pInfo->IsNew == isNew)
483 pInfo->KillMe = true;
500 void UserMessages::_DecRefCounter()
502 if (--m_HookCount == 0)
504 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
505 SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
506 SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
508 SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
509 SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
510 SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
511 SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
516 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
517 void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
519 #if SOURCE_ENGINE == SE_DOTA
520 OnStartMessage_Pre(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
521 #elif SOURCE_ENGINE == SE_CSGO
522 OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
524 if (m_FakeMetaRes == MRES_SUPERCEDE)
526 int size = msg.ByteSize();
527 uint8 *data = (uint8 *)stackalloc(size);
528 msg.SerializePartialToArray(data, size);
529 m_InterceptBuffer->ParsePartialFromArray(data, size);
533 m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
536 #if SOURCE_ENGINE == SE_DOTA
537 OnStartMessage_Post(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
538 #elif SOURCE_ENGINE == SE_CSGO
539 OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
543 if (m_FakeMetaRes == MRES_SUPERCEDE)
544 RETURN_META(MRES_SUPERCEDE);
546 RETURN_META(MRES_IGNORED);
549 void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
552 RETURN_META(MRES_IGNORED);
556 #ifdef USE_PROTOBUF_USERMESSAGES
557 #define UM_RETURN_META_VALUE(res, val) \
558 m_FakeMetaRes = res; \
561 #define UM_RETURN_META(res) \
562 m_FakeMetaRes = res; \
565 #define UM_RETURN_META_VALUE(res, val) \
566 RETURN_META_VALUE(res, val)
568 #define UM_RETURN_META(res) \
572 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
573 protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
574 #elif SOURCE_ENGINE >= SE_LEFT4DEAD
575 bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
577 bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
580 bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
581 bool is_hook_empty = m_msgHooks[msg_type].empty();
583 if ((is_intercept_empty && is_hook_empty)
584 || (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
587 UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
591 m_CurRecFilter = filter;
593 m_BlockEndPost = false;
595 if (!is_intercept_empty)
597 #ifdef USE_PROTOBUF_USERMESSAGES
598 if (m_InterceptBuffer)
599 delete m_InterceptBuffer;
600 m_InterceptBuffer = GetMessagePrototype(msg_type)->New();
602 UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
604 m_InterceptBuffer.Reset();
605 UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
609 UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
612 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
613 protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
614 #elif SOURCE_ENGINE >= SE_LEFT4DEAD
615 bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
617 bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
622 UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
625 #ifdef USE_PROTOBUF_USERMESSAGES
626 if (m_FakeMetaRes == MRES_SUPERCEDE)
627 m_OrigBuffer = m_InterceptBuffer;
629 m_OrigBuffer = m_FakeEngineBuffer;
631 m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
634 UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
637 void UserMessages::OnMessageEnd_Post()
641 UM_RETURN_META(MRES_IGNORED);
650 pList = &m_msgIntercepts[m_CurId];
651 for (iter=pList->begin(); iter!=pList->end(); )
654 if (m_BlockEndPost && !pInfo->IsNew)
658 pInfo->IsHooked = true;
659 pInfo->Callback->OnUserMessageSent(m_CurId);
662 pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
667 iter = pList->erase(iter);
668 m_FreeListeners.push(pInfo);
673 pInfo->IsHooked = false;
677 pList = &m_msgHooks[m_CurId];
678 for (iter=pList->begin(); iter!=pList->end(); )
681 if (m_BlockEndPost && !pInfo->IsNew)
685 pInfo->IsHooked = true;
686 pInfo->Callback->OnUserMessageSent(m_CurId);
689 pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
694 iter = pList->erase(iter);
695 m_FreeListeners.push(pInfo);
700 pInfo->IsHooked = false;
705 void UserMessages::OnMessageEnd_Pre()
709 UM_RETURN_META(MRES_IGNORED);
717 bool intercepted = false;
718 bool handled = false;
720 pList = &m_msgIntercepts[m_CurId];
721 for (iter=pList->begin(); iter!=pList->end(); )
724 pInfo->IsHooked = true;
725 #ifdef USE_PROTOBUF_USERMESSAGES
726 res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
728 res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
740 m_FreeListeners.push(pInfo);
744 pInfo->IsHooked = false;
752 iter = pList->erase(iter);
753 m_FreeListeners.push(pInfo);
763 iter = pList->erase(iter);
764 m_FreeListeners.push(pInfo);
771 pInfo->IsHooked = false;
775 if (!handled && intercepted)
777 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
778 ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
780 bf_write *engine_bfw;
781 #if SOURCE_ENGINE >= SE_LEFT4DEAD
782 engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId));
784 engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
786 m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
787 engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
788 ENGINE_CALL(MessageEnd)();
789 #endif // SE_CSGO || SE_DOTA
793 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
794 int size = m_OrigBuffer->ByteSize();
795 uint8 *data = (uint8 *)stackalloc(size);
796 m_OrigBuffer->SerializePartialToArray(data, size);
798 protobuf::Message *pTempMsg = GetMessagePrototype(m_CurId)->New();
799 pTempMsg->ParsePartialFromArray(data, size);
801 bf_write *pTempMsg = m_OrigBuffer;
804 pList = &m_msgHooks[m_CurId];
805 for (iter=pList->begin(); iter!=pList->end(); )
808 pInfo->IsHooked = true;
809 pInfo->Callback->OnUserMessage(m_CurId, pTempMsg, m_CurRecFilter);
813 iter = pList->erase(iter);
814 m_FreeListeners.push(pInfo);
819 pInfo->IsHooked = false;
823 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
828 UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
830 m_BlockEndPost = true;
831 UM_RETURN_META(MRES_SUPERCEDE);