dvander@592: /**
ds@653: * vim: set ts=4 :
ds@1330: * =============================================================================
dvander@1231: * SourceMod
ds@3099: * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
ds@1330: * =============================================================================
ds@653: *
ds@1330: * This program is free software; you can redistribute it and/or modify it under
ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330: * Free Software Foundation.
dvander@1231: *
ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1330: * details.
dvander@1231: *
ds@1330: * You should have received a copy of the GNU General Public License along with
ds@1330: * this program. If not, see .
dvander@1231: *
ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1330: * this exception to all derivative works. AlliedModders LLC defines further
ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330: * or .
ds@653: *
ds@653: * Version: $Id$
ds@653: */
dvander@592:
dvander@592: #include "UserMessages.h"
ds@765: #include "sm_stringutil.h"
dvander@592:
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3743: #include
skamonkey@3743: #endif
skamonkey@3743:
dvander@616: UserMessages g_UserMsgs;
dvander@592:
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3743: SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
skamonkey@3743: #else
ds@3099: #if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400: SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int, const char *);
ds@2400: #else
dvander@592: SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
ds@2400: #endif
dvander@592: SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
skamonkey@3743: #endif // ==SE_CSGO
dvander@592:
skamonkey@3743: UserMessages::UserMessages()
skamonkey@3743: #ifndef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: : m_InterceptBuffer(m_pBase, 2500)
dvander@592: {
dvander@592: m_Names = sm_trie_create();
skamonkey@3743: #else
skamonkey@3743: : m_InterceptBuffer(NULL)
skamonkey@3743: {
skamonkey@3743: #endif
dvander@592: m_HookCount = 0;
dvander@592: m_InExec = false;
dvander@592: m_InHook = false;
dvander@592: m_CurFlags = 0;
dvander@592: m_CurId = INVALID_MESSAGE_ID;
dvander@592: }
dvander@592:
dvander@616: UserMessages::~UserMessages()
dvander@592: {
skamonkey@3743: #ifndef USE_PROTOBUF_USERMESSAGES
dvander@592: sm_trie_destroy(m_Names);
skamonkey@3743: #endif
faluco@641:
faluco@641: CStack::iterator iter;
faluco@641: for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
faluco@641: {
faluco@641: delete (*iter);
faluco@641: }
faluco@641: m_FreeListeners.popall();
dvander@592: }
dvander@592:
ds@765: void UserMessages::OnSourceModStartup(bool late)
ds@765: {
skamonkey@3743: #ifndef USE_PROTOBUF_USERMESSAGES
ds@765: /* -1 means SourceMM was unable to get the user message list */
ds@765: m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1);
skamonkey@3743: #endif
ds@765: }
ds@765:
dvander@616: void UserMessages::OnSourceModAllInitialized()
dvander@592: {
dvander@592: g_ShareSys.AddInterface(NULL, this);
dvander@592: }
dvander@592:
dvander@616: void UserMessages::OnSourceModAllShutdown()
dvander@592: {
dvander@592: if (m_HookCount)
dvander@592: {
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
skamonkey@3743: #else
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
skamonkey@3743: #endif
dvander@592: }
dvander@592: m_HookCount = 0;
dvander@592: }
dvander@592:
dvander@616: int UserMessages::GetMessageIndex(const char *msg)
dvander@592: {
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3743: // Can split this per engine and/or game later
skamonkey@3743: return g_Cstrike15UsermessageHelpers.GetIndex(msg);
skamonkey@3743: #else
dvander@592: int msgid;
ds@698:
dvander@592: if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast(&msgid)))
dvander@592: {
ds@765: if (m_FallbackSearch)
ds@765: {
ds@765: char msgbuf[64];
ds@765: int size;
ds@765: msgid = 0;
ds@765:
ds@765: while (gamedll->GetUserMessageInfo(msgid, msgbuf, sizeof(msgbuf), size))
ds@765: {
ds@765: if (strcmp(msgbuf, msg) == 0)
ds@765: {
ds@765: sm_trie_insert(m_Names, msg, reinterpret_cast(msgid));
ds@765: return msgid;
ds@765: }
ds@765: msgid++;
ds@765: }
ds@765: }
ds@765:
ds@698: msgid = g_SMAPI->FindUserMessage(msg);
dvander@592:
ds@698: if (msgid != INVALID_MESSAGE_ID)
dvander@592: {
ds@698: sm_trie_insert(m_Names, msg, reinterpret_cast(msgid));
dvander@592: }
dvander@592: }
dvander@592:
dvander@592: return msgid;
skamonkey@3743: #endif
dvander@592: }
dvander@592:
ds@765: bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
ds@765: {
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3743: const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
skamonkey@3743: if (!pszName)
skamonkey@3743: return false;
skamonkey@3743:
skamonkey@3743: strncopy(buffer, pszName, maxlength);
skamonkey@3743: return true;
skamonkey@3743: #else
ds@765: if (m_FallbackSearch)
ds@765: {
ds@765: int size;
ds@765: return gamedll->GetUserMessageInfo(msgid, buffer, maxlength, size);
ds@765: }
ds@766:
ds@765: const char *msg = g_SMAPI->GetUserMessage(msgid);
ds@765:
ds@765: if (msg)
ds@765: {
ds@765: strncopy(buffer, msg, maxlength);
ds@765: return true;
ds@765: }
ds@765:
ds@765: return false;
skamonkey@3743: #endif
ds@765: }
ds@765:
skamonkey@3743: bf_write *UserMessages::StartBitBufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
dvander@592: {
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: return NULL;
skamonkey@3743: #else
dvander@592: bf_write *buffer;
faluco@593:
faluco@593: if (m_InExec || m_InHook)
dvander@592: {
dvander@592: return NULL;
dvander@592: }
dvander@592: if (msg_id < 0 || msg_id >= 255)
dvander@592: {
dvander@592: return NULL;
dvander@592: }
dvander@592:
faluco@593: m_CellRecFilter.Initialize(players, playersNum);
dvander@592:
dvander@592: m_CurFlags = flags;
dvander@592: if (m_CurFlags & USERMSG_INITMSG)
dvander@592: {
faluco@593: m_CellRecFilter.SetToInit(true);
dvander@592: }
dvander@592: if (m_CurFlags & USERMSG_RELIABLE)
dvander@592: {
faluco@593: m_CellRecFilter.SetToReliable(true);
dvander@592: }
dvander@592:
dvander@592: m_InExec = true;
dvander@592:
faluco@1250: if (m_CurFlags & USERMSG_BLOCKHOOKS)
dvander@592: {
ds@3099: #if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400: buffer = ENGINE_CALL(UserMessageBegin)(static_cast(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
ds@2400: #else
faluco@1250: buffer = ENGINE_CALL(UserMessageBegin)(static_cast(&m_CellRecFilter), msg_id);
ds@2400: #endif
faluco@1250: } else {
ds@3099: #if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400: buffer = engine->UserMessageBegin(static_cast(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
ds@2400: #else
dvander@592: buffer = engine->UserMessageBegin(static_cast(&m_CellRecFilter), msg_id);
ds@2400: #endif
dvander@592: }
dvander@592:
dvander@592: return buffer;
skamonkey@3743: #endif // USE_PROTOBUF_USERMESSAGES
skamonkey@3743: }
skamonkey@3743:
skamonkey@3743: google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
skamonkey@3743: {
skamonkey@3743: #ifndef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: return NULL;
skamonkey@3743: #else
skamonkey@3743: protobuf::Message *buffer;
skamonkey@3743:
skamonkey@3743: if (m_InExec || m_InHook)
skamonkey@3743: {
skamonkey@3743: return NULL;
skamonkey@3743: }
skamonkey@3743: if (msg_id < 0 || msg_id >= 255)
skamonkey@3743: {
skamonkey@3743: return NULL;
skamonkey@3743: }
skamonkey@3743:
skamonkey@3743: m_CurId = msg_id;
skamonkey@3743: m_CellRecFilter.Initialize(players, playersNum);
skamonkey@3743:
skamonkey@3743: m_CurFlags = flags;
skamonkey@3743: if (m_CurFlags & USERMSG_INITMSG)
skamonkey@3743: {
skamonkey@3743: m_CellRecFilter.SetToInit(true);
skamonkey@3743: }
skamonkey@3743: if (m_CurFlags & USERMSG_RELIABLE)
skamonkey@3743: {
skamonkey@3743: m_CellRecFilter.SetToReliable(true);
skamonkey@3743: }
skamonkey@3743:
skamonkey@3743: m_InExec = true;
skamonkey@3743:
skamonkey@3743: if (m_CurFlags & USERMSG_BLOCKHOOKS)
skamonkey@3743: {
skamonkey@3743: // direct message creation, return buffer "from engine". keep track
skamonkey@3743: m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
skamonkey@3743: buffer = m_FakeEngineBuffer;
skamonkey@3743: } else {
skamonkey@3757: char messageName[32];
skamonkey@3757: if (!GetMessageName(msg_id, messageName, sizeof(messageName)))
skamonkey@3757: {
skamonkey@3757: m_InExec = false;
skamonkey@3757: return NULL;
skamonkey@3757: }
skamonkey@3757:
skamonkey@3757: protobuf::Message *msg = OnStartMessage_Pre(static_cast(&m_CellRecFilter), msg_id, messageName);
skamonkey@3743: switch (m_FakeMetaRes)
skamonkey@3743: {
skamonkey@3743: case MRES_IGNORED:
skamonkey@3743: case MRES_HANDLED:
skamonkey@3743: m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
skamonkey@3743: buffer = m_FakeEngineBuffer;
skamonkey@3743: break;
skamonkey@3743:
skamonkey@3743: case MRES_OVERRIDE:
skamonkey@3743: m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
skamonkey@3743: // fallthrough
skamonkey@3743: case MRES_SUPERCEDE:
skamonkey@3743: buffer = msg;
skamonkey@3743: break;
skamonkey@3743: }
skamonkey@3743:
skamonkey@3757: OnStartMessage_Post(static_cast(&m_CellRecFilter), msg_id, messageName);
skamonkey@3743: }
skamonkey@3743:
skamonkey@3743: return buffer;
skamonkey@3743: #endif // USE_PROTOBUF_USERMESSAGES
dvander@592: }
dvander@592:
dvander@616: bool UserMessages::EndMessage()
dvander@592: {
dvander@592: if (!m_InExec)
dvander@592: {
dvander@592: return false;
dvander@592: }
dvander@592:
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3743: if (m_CurFlags & USERMSG_BLOCKHOOKS)
skamonkey@3743: {
skamonkey@3743: ENGINE_CALL(SendUserMessage)(static_cast(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
skamonkey@3743: delete m_FakeEngineBuffer;
skamonkey@3743: m_FakeEngineBuffer = NULL;
skamonkey@3743: } else {
skamonkey@3743: OnMessageEnd_Pre();
skamonkey@3743:
skamonkey@3743: switch (m_FakeMetaRes)
skamonkey@3743: {
skamonkey@3743: case MRES_IGNORED:
skamonkey@3743: case MRES_HANDLED:
skamonkey@3743: case MRES_OVERRIDE:
skamonkey@3743: engine->SendUserMessage(static_cast(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
skamonkey@3743: delete m_FakeEngineBuffer;
skamonkey@3743: m_FakeEngineBuffer = NULL;
skamonkey@3743: break;
skamonkey@3743: //case MRES_SUPERCEDE:
skamonkey@3743: }
skamonkey@3743:
skamonkey@3743: OnMessageEnd_Post();
skamonkey@3743: }
skamonkey@3743: #else
faluco@1250: if (m_CurFlags & USERMSG_BLOCKHOOKS)
dvander@592: {
faluco@1250: ENGINE_CALL(MessageEnd)();
faluco@1250: } else {
dvander@592: engine->MessageEnd();
dvander@592: }
skamonkey@3743: #endif // SE_CSGO
dvander@592:
dvander@592: m_InExec = false;
dvander@592: m_CurFlags = 0;
faluco@593: m_CellRecFilter.Reset();
dvander@592:
dvander@592: return true;
dvander@592: }
dvander@592:
skamonkey@3743: UserMessageType UserMessages::GetUserMessageType() const
skamonkey@3743: {
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: return UM_Protobuf;
skamonkey@3743: #else
skamonkey@3743: return UM_BitBuf;
skamonkey@3743: #endif
skamonkey@3743: }
skamonkey@3743:
dvander@2636: bool UserMessages::HookUserMessage2(int msg_id,
dvander@2636: IUserMessageListener *pListener,
dvander@2636: bool intercept)
dvander@2636: {
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
skamonkey@3743: #else
skamonkey@3743: return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
skamonkey@3743: #endif
dvander@2636: }
dvander@2636:
dvander@2636: bool UserMessages::UnhookUserMessage2(int msg_id,
dvander@2636: IUserMessageListener *pListener,
dvander@2636: bool intercept)
dvander@2636: {
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
skamonkey@3743: #else
skamonkey@3743: return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
skamonkey@3743: #endif
dvander@2636: }
dvander@2636:
dvander@616: bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
dvander@592: {
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
skamonkey@3743: #else
skamonkey@3743: return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
skamonkey@3743: #endif
dvander@2636: }
dvander@2636:
dvander@2636: bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
dvander@2636: {
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
skamonkey@3743: #else
skamonkey@3743: return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
skamonkey@3743: #endif
dvander@2636: }
dvander@2636:
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: bool UserMessages::InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743: #else
skamonkey@3743: bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743: #endif
dvander@2636: {
dvander@592: if (msg_id < 0 || msg_id >= 255)
dvander@592: {
dvander@592: return false;
dvander@592: }
dvander@592:
faluco@593: ListenerInfo *pInfo;
faluco@593: if (m_FreeListeners.empty())
faluco@593: {
faluco@593: pInfo = new ListenerInfo;
faluco@593: } else {
faluco@593: pInfo = m_FreeListeners.front();
faluco@593: m_FreeListeners.pop();
faluco@593: }
faluco@593:
faluco@593: pInfo->Callback = pListener;
faluco@593: pInfo->IsHooked = false;
faluco@593: pInfo->KillMe = false;
dvander@2636: pInfo->IsNew = isNew;
faluco@593:
dvander@592: if (!m_HookCount++)
dvander@592: {
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
kyle@3819: SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
kyle@3819: SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
skamonkey@3743: #else
kyle@3819: SH_ADD_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
kyle@3819: SH_ADD_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
kyle@3819: SH_ADD_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
kyle@3819: SH_ADD_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
skamonkey@3743: #endif
dvander@592: }
dvander@592:
dvander@592: if (intercept)
dvander@592: {
faluco@593: m_msgIntercepts[msg_id].push_back(pInfo);
dvander@592: } else {
faluco@593: m_msgHooks[msg_id].push_back(pInfo);
dvander@592: }
dvander@592:
dvander@592: return true;
dvander@592: }
dvander@592:
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: bool UserMessages::InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743: #else
skamonkey@3743: bool UserMessages::InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
skamonkey@3743: #endif
dvander@2636: {
faluco@593: MsgList *pList;
dvander@592: MsgIter iter;
faluco@593: ListenerInfo *pInfo;
dvander@592: bool deleted = false;
dvander@592:
dvander@592: if (msg_id < 0 || msg_id >= 255)
dvander@592: {
dvander@592: return false;
dvander@592: }
dvander@592:
faluco@593: pList = (intercept) ? &m_msgIntercepts[msg_id] : &m_msgHooks[msg_id];
faluco@593: for (iter=pList->begin(); iter!=pList->end(); iter++)
dvander@592: {
faluco@593: pInfo = (*iter);
dvander@2636: if (pInfo->Callback == pListener && pInfo->IsNew == isNew)
dvander@592: {
faluco@593: if (pInfo->IsHooked)
faluco@593: {
faluco@593: pInfo->KillMe = true;
faluco@593: return true;
faluco@593: }
faluco@593: pList->erase(iter);
dvander@592: deleted = true;
dvander@592: break;
dvander@592: }
dvander@592: }
dvander@592:
faluco@593: if (deleted)
faluco@593: {
faluco@593: _DecRefCounter();
faluco@593: }
faluco@593:
faluco@593: return deleted;
faluco@593: }
faluco@593:
dvander@616: void UserMessages::_DecRefCounter()
faluco@593: {
faluco@593: if (--m_HookCount == 0)
dvander@592: {
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
skamonkey@3743: #else
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Pre), false);
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, UserMessageBegin, engine, SH_MEMBER(this, &UserMessages::OnStartMessage_Post), true);
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Pre), false);
kyle@3819: SH_REMOVE_HOOK(IVEngineServer, MessageEnd, engine, SH_MEMBER(this, &UserMessages::OnMessageEnd_Post), true);
skamonkey@3743: #endif
dvander@592: }
dvander@592: }
dvander@592:
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3743: void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
skamonkey@3743: {
skamonkey@3743: OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
skamonkey@3743: if (m_FakeMetaRes == MRES_SUPERCEDE)
skamonkey@3743: {
skamonkey@3778: int size = msg.ByteSize();
skamonkey@3778: uint8 *data = (uint8 *)stackalloc(size);
skamonkey@3778: msg.SerializePartialToArray(data, size);
skamonkey@3786: m_InterceptBuffer->ParsePartialFromArray(data, size);
skamonkey@3743: }
skamonkey@3743: else
skamonkey@3743: {
skamonkey@3759: m_FakeEngineBuffer = &const_cast(msg);
skamonkey@3743: }
skamonkey@3743:
skamonkey@3786: OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
skamonkey@3786:
skamonkey@3743: OnMessageEnd_Pre();
skamonkey@3743: if (m_FakeMetaRes == MRES_SUPERCEDE)
skamonkey@3743: RETURN_META(MRES_SUPERCEDE);
skamonkey@3743:
skamonkey@3743: RETURN_META(MRES_IGNORED);
skamonkey@3743: }
skamonkey@3743:
skamonkey@3743: void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
skamonkey@3743: {
skamonkey@3743: OnMessageEnd_Post();
skamonkey@3743: RETURN_META(MRES_IGNORED);
skamonkey@3743: }
skamonkey@3743: #endif
skamonkey@3743:
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: #define UM_RETURN_META_VALUE(res, val) \
skamonkey@3743: m_FakeMetaRes = res; \
skamonkey@3743: return val;
skamonkey@3743:
skamonkey@3743: #define UM_RETURN_META(res) \
skamonkey@3743: m_FakeMetaRes = res; \
skamonkey@3743: return;
skamonkey@3743: #else
skamonkey@3743: #define UM_RETURN_META_VALUE(res, val) \
skamonkey@3743: RETURN_META_VALUE(res, val)
skamonkey@3743:
skamonkey@3743: #define UM_RETURN_META(res) \
skamonkey@3743: RETURN_META(res)
skamonkey@3743: #endif
skamonkey@3743:
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3743: protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
skamonkey@3743: #elif SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400: bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
ds@2400: #else
dvander@616: bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
ds@2400: #endif
dvander@592: {
dvander@592: bool is_intercept_empty = m_msgIntercepts[msg_type].empty();
dvander@592: bool is_hook_empty = m_msgHooks[msg_type].empty();
dvander@592:
faluco@593: if ((is_intercept_empty && is_hook_empty)
faluco@1250: || (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
dvander@592: {
dvander@592: m_InHook = false;
skamonkey@3743: UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592: }
dvander@592:
dvander@592: m_CurId = msg_type;
dvander@592: m_CurRecFilter = filter;
dvander@592: m_InHook = true;
faluco@597: m_BlockEndPost = false;
dvander@592:
dvander@592: if (!is_intercept_empty)
dvander@592: {
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: if (m_InterceptBuffer)
skamonkey@3743: delete m_InterceptBuffer;
skamonkey@3743: m_InterceptBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
skamonkey@3743: UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
skamonkey@3743: #else
faluco@593: m_InterceptBuffer.Reset();
skamonkey@3743: UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
skamonkey@3743: #endif
dvander@592: }
dvander@592:
skamonkey@3743: UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592: }
dvander@592:
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3743: protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
skamonkey@3743: #elif SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400: bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
ds@2400: #else
dvander@616: bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
ds@2400: #endif
dvander@592: {
dvander@592: if (!m_InHook)
dvander@592: {
skamonkey@3743: UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592: }
dvander@592:
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3786: if (m_FakeMetaRes == MRES_SUPERCEDE)
skamonkey@3786: m_OrigBuffer = m_InterceptBuffer;
skamonkey@3786: else
skamonkey@3786: m_OrigBuffer = m_FakeEngineBuffer;
skamonkey@3743: #else
dvander@592: m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
skamonkey@3743: #endif
dvander@592:
skamonkey@3743: UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
dvander@592: }
dvander@592:
dvander@616: void UserMessages::OnMessageEnd_Post()
dvander@592: {
dvander@2636: if (!m_InHook)
dvander@592: {
skamonkey@3743: UM_RETURN_META(MRES_IGNORED);
dvander@592: }
dvander@592:
faluco@593: MsgList *pList;
dvander@592: MsgIter iter;
faluco@593: ListenerInfo *pInfo;
faluco@593:
pred@2577: m_InHook = false;
pred@2577:
faluco@593: pList = &m_msgIntercepts[m_CurId];
faluco@593: for (iter=pList->begin(); iter!=pList->end(); )
faluco@593: {
faluco@593: pInfo = (*iter);
dvander@2636: if (m_BlockEndPost && !pInfo->IsNew)
dvander@2636: {
dvander@2636: continue;
dvander@2636: }
faluco@593: pInfo->IsHooked = true;
faluco@593: pInfo->Callback->OnUserMessageSent(m_CurId);
dvander@2636: if (pInfo->IsNew)
dvander@2636: {
dvander@2636: pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
dvander@2636: }
dvander@592:
faluco@593: if (pInfo->KillMe)
faluco@593: {
faluco@593: iter = pList->erase(iter);
faluco@593: m_FreeListeners.push(pInfo);
faluco@593: _DecRefCounter();
faluco@593: continue;
faluco@593: }
faluco@593:
faluco@593: pInfo->IsHooked = false;
faluco@593: iter++;
dvander@592: }
dvander@592:
faluco@593: pList = &m_msgHooks[m_CurId];
faluco@594: for (iter=pList->begin(); iter!=pList->end(); )
dvander@592: {
faluco@593: pInfo = (*iter);
dvander@2636: if (m_BlockEndPost && !pInfo->IsNew)
dvander@2636: {
dvander@2636: continue;
dvander@2636: }
faluco@594: pInfo->IsHooked = true;
faluco@593: pInfo->Callback->OnUserMessageSent(m_CurId);
dvander@2636: if (pInfo->IsNew)
dvander@2636: {
dvander@2636: pInfo->Callback->OnPostUserMessage(m_CurId, !m_BlockEndPost);
dvander@2636: }
faluco@593:
faluco@593: if (pInfo->KillMe)
faluco@593: {
faluco@593: iter = pList->erase(iter);
faluco@593: m_FreeListeners.push(pInfo);
faluco@593: _DecRefCounter();
faluco@593: continue;
faluco@593: }
faluco@593:
faluco@593: pInfo->IsHooked = false;
faluco@593: iter++;
dvander@592: }
dvander@592: }
dvander@592:
dvander@616: void UserMessages::OnMessageEnd_Pre()
dvander@592: {
dvander@592: if (!m_InHook)
dvander@592: {
skamonkey@3743: UM_RETURN_META(MRES_IGNORED);
dvander@592: }
dvander@592:
faluco@593: MsgList *pList;
dvander@592: MsgIter iter;
faluco@593: ListenerInfo *pInfo;
faluco@593:
dvander@592: ResultType res;
dvander@592: bool intercepted = false;
dvander@592: bool handled = false;
dvander@592:
faluco@593: pList = &m_msgIntercepts[m_CurId];
faluco@593: for (iter=pList->begin(); iter!=pList->end(); )
dvander@592: {
faluco@593: pInfo = (*iter);
faluco@593: pInfo->IsHooked = true;
skamonkey@3743: #ifdef USE_PROTOBUF_USERMESSAGES
skamonkey@3743: res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
skamonkey@3743: #else
faluco@593: res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
skamonkey@3743: #endif
faluco@593:
faluco@597: intercepted = true;
faluco@597:
faluco@593: switch (res)
dvander@592: {
faluco@593: case Pl_Stop:
faluco@593: {
faluco@593: if (pInfo->KillMe)
faluco@593: {
faluco@593: pList->erase(iter);
faluco@593: m_FreeListeners.push(pInfo);
faluco@593: _DecRefCounter();
faluco@593: goto supercede;
faluco@593: }
faluco@593: pInfo->IsHooked = false;
faluco@593: goto supercede;
faluco@593: }
faluco@593: case Pl_Handled:
faluco@593: {
faluco@593: handled = true;
faluco@593: if (pInfo->KillMe)
faluco@593: {
faluco@593: iter = pList->erase(iter);
faluco@593: m_FreeListeners.push(pInfo);
faluco@593: _DecRefCounter();
faluco@593: continue;
faluco@593: }
faluco@593: break;
faluco@593: }
faluco@593: default:
faluco@593: {
faluco@593: if (pInfo->KillMe)
faluco@593: {
faluco@593: iter = pList->erase(iter);
faluco@593: m_FreeListeners.push(pInfo);
faluco@593: _DecRefCounter();
faluco@593: continue;
faluco@593: }
faluco@597: break;
faluco@593: }
dvander@592: }
faluco@593: pInfo->IsHooked = false;
faluco@593: iter++;
dvander@592: }
dvander@592:
dvander@2734: if (!handled && intercepted)
dvander@592: {
skamonkey@3743: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3743: ENGINE_CALL(SendUserMessage)(static_cast(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
skamonkey@3743: #else
faluco@593: bf_write *engine_bfw;
ds@3099: #if SOURCE_ENGINE >= SE_LEFT4DEAD
ds@2400: engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId));
ds@2400: #else
dvander@592: engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId);
ds@2400: #endif
dvander@592: m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
dvander@592: engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
dvander@592: ENGINE_CALL(MessageEnd)();
skamonkey@3743: #endif // SE_CSGO
dvander@592: }
dvander@592:
dvander@592: {
skamonkey@3779: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3778: int size = m_OrigBuffer->ByteSize();
skamonkey@3778: uint8 *data = (uint8 *)stackalloc(size);
skamonkey@3778: m_OrigBuffer->SerializePartialToArray(data, size);
skamonkey@3778: protobuf::Message *pTempMsg = g_Cstrike15UsermessageHelpers.GetPrototype(m_CurId)->New();
skamonkey@3786: pTempMsg->ParsePartialFromArray(data, size);
skamonkey@3779: #else
skamonkey@3779: bf_write *pTempMsg = m_OrigBuffer;
skamonkey@3779: #endif
faluco@593:
skamonkey@3778: pList = &m_msgHooks[m_CurId];
skamonkey@3778: for (iter=pList->begin(); iter!=pList->end(); )
faluco@593: {
skamonkey@3778: pInfo = (*iter);
skamonkey@3778: pInfo->IsHooked = true;
skamonkey@3778: pInfo->Callback->OnUserMessage(m_CurId, pTempMsg, m_CurRecFilter);
skamonkey@3778:
skamonkey@3778: if (pInfo->KillMe)
skamonkey@3778: {
skamonkey@3778: iter = pList->erase(iter);
skamonkey@3778: m_FreeListeners.push(pInfo);
skamonkey@3778: _DecRefCounter();
skamonkey@3778: continue;
skamonkey@3778: }
skamonkey@3778:
skamonkey@3778: pInfo->IsHooked = false;
skamonkey@3778: iter++;
faluco@593: }
faluco@593:
skamonkey@3779: #if SOURCE_ENGINE == SE_CSGO
skamonkey@3778: delete pTempMsg;
skamonkey@3779: #endif
dvander@592: }
dvander@592:
skamonkey@3743: UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
dvander@592: supercede:
faluco@597: m_BlockEndPost = true;
skamonkey@3743: UM_RETURN_META(MRES_SUPERCEDE);
dvander@592: }