dvander@592: /** dvander@4073: * vim: set ts=4 sw=4 tw=99 noet : 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@3872: #include "logic_bridge.h" dvander@592: skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: #include skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3743: #include skamonkey@3743: #endif skamonkey@3743: dvander@616: UserMessages g_UserMsgs; dvander@592: skamonkey@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA 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: { 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: { 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@3872: sharesys->AddInterface(NULL, this); dvander@592: } dvander@592: dvander@616: void UserMessages::OnSourceModAllShutdown() dvander@592: { dvander@592: if (m_HookCount) dvander@592: { skamonkey@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA 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@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: // Can split this per engine and/or game later skamonkey@3855: return g_DotaUsermessageHelpers.GetIndex(msg); skamonkey@3855: #elif 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@4073: dvander@592: int msgid; dvander@4073: if (!m_Names.retrieve(msg, &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: { dvander@4073: m_Names.insert(msg, 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@4073: m_Names.insert(msg, msgid); 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@3855: #ifdef USE_PROTOBUF_USERMESSAGES skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: const char *pszName = g_DotaUsermessageHelpers.GetName(msgid); skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3743: const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid); skamonkey@3855: #endif 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@3855: m_FakeEngineBuffer = GetMessagePrototype(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@3855: m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New(); skamonkey@3743: buffer = m_FakeEngineBuffer; skamonkey@3743: break; skamonkey@3743: skamonkey@3743: case MRES_OVERRIDE: skamonkey@3855: m_FakeEngineBuffer = GetMessagePrototype(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@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA 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@3855: #endif // SE_CSGO || SE_DOTA 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@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA 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@3861: const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type) skamonkey@3855: { skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: return g_DotaUsermessageHelpers.GetPrototype(msg_type); skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3855: return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type); skamonkey@3855: #endif skamonkey@3855: } skamonkey@3855: #endif skamonkey@3855: skamonkey@3855: #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@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA 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@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA skamonkey@3743: void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg) skamonkey@3743: { skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: OnStartMessage_Pre(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type)); skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3743: OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type)); skamonkey@3855: #endif 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@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: OnStartMessage_Post(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type)); skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3786: OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type)); skamonkey@3855: #endif 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@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA 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@3855: m_InterceptBuffer = GetMessagePrototype(msg_type)->New(); skamonkey@3855: 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@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA 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@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA 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@3855: #endif // SE_CSGO || SE_DOTA dvander@592: } dvander@592: dvander@592: { skamonkey@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA skamonkey@3778: int size = m_OrigBuffer->ByteSize(); skamonkey@3778: uint8 *data = (uint8 *)stackalloc(size); skamonkey@3778: m_OrigBuffer->SerializePartialToArray(data, size); skamonkey@3855: skamonkey@3855: protobuf::Message *pTempMsg = GetMessagePrototype(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@3855: #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA 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: }