From 312e26a5cfba5263bd165832f8dc68d46a8a2312 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Tue, 22 Jan 2013 21:43:12 -0500 Subject: [PATCH] Added initial support for protobuf usermessages on CS:GO (bug 5579, r=asherkin). --- AMBuildScript | 1 - core/AMBuilder | 43 +- core/HalfLife2.cpp | 92 +++- core/MenuStyle_Radio.cpp | 30 +- core/MenuStyle_Radio.h | 12 +- core/UserMessagePBHelpers.h | 853 +++++++++++++++++++++++++++++++ core/UserMessages.cpp | 381 +++++++++++++- core/UserMessages.h | 55 +- core/smn_bitbuffer.cpp | 7 + core/smn_console.cpp | 16 + core/smn_hudtext.cpp | 36 +- core/smn_protobuf.cpp | 823 +++++++++++++++++++++++++++++ core/smn_usermsgs.cpp | 100 +++- core/smn_usermsgs.h | 18 +- core/sourcemod.h | 2 - plugins/funcommands/blind.sp | 36 +- plugins/funcommands/drug.sp | 72 ++- plugins/include/core.inc | 61 +++ plugins/include/protobuf.inc | 433 ++++++++++++++++ plugins/include/sourcemod.inc | 1 + plugins/include/usermessages.inc | 20 +- public/IUserMessages.h | 124 ++++- 22 files changed, 3106 insertions(+), 110 deletions(-) create mode 100644 core/UserMessagePBHelpers.h create mode 100644 core/smn_protobuf.cpp create mode 100644 plugins/include/protobuf.inc diff --git a/AMBuildScript b/AMBuildScript index e763bf0b..6f6b3b24 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -124,7 +124,6 @@ class SM: self.compiler.AddToListVar('CFLAGS', '-m32') self.compiler.AddToListVar('POSTLINKFLAGS', '-m32') self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions') - self.compiler.AddToListVar('CXXFLAGS', '-fno-rtti') self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics') self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor') self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual') diff --git a/core/AMBuilder b/core/AMBuilder index e312017f..9709c81a 100644 --- a/core/AMBuilder +++ b/core/AMBuilder @@ -1,5 +1,6 @@ # vim: set ts=2 sw=2 tw=99 noet ft=python: import os +from ambuild.command import SymlinkCommand for i in SM.sdkInfo: sdk = SM.sdkInfo[i] @@ -10,9 +11,35 @@ for i in SM.sdkInfo: compiler = SM.DefaultHL2Compiler('core', i) + if i == 'csgo': + compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache[sdk['sdk']], 'common', 'protobuf-2.3.0', 'src')) + compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache[sdk['sdk']], 'public', 'engine', 'protobuf')) + compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache[sdk['sdk']], 'public', 'game', 'shared', 'csgo', 'protobuf')) + extension = AMBuild.AddJob(name) binary = Cpp.LibraryBuilder(name, AMBuild, extension, compiler) SM.PreSetupHL2Job(extension, binary, i) + + if i == 'csgo': + if AMBuild.target['platform'] == 'linux': + link = os.path.join(os.path.join(AMBuild.outputFolder, extension.workFolder), 'libprotobuf.a') + target = os.path.join(os.path.join(AMBuild.cache[sdk['sdk']], 'lib', 'linux32', 'release'), 'libprotobuf.a') + try: + os.lstat(link) + except: + extension.AddCommand(SymlinkCommand(link, target)) + elif AMBuild.target['platform'] == 'darwin': + link = os.path.join(os.path.join(AMBuild.outputFolder, extension.workFolder), 'libprotobuf.a') + target = os.path.join(os.path.join(AMBuild.cache[sdk['sdk']], 'lib', 'osx32', 'release'), 'libprotobuf.a') + try: + os.lstat(link) + except: + extension.AddCommand(SymlinkCommand(link, target)) + elif AMBuild.target['platform'] == 'windows': + libPath = os.path.join(AMBuild.cache[sdk['sdk']], 'lib', 'win32', 'release', 'vs2010', 'libprotobuf.lib') + binary.RebuildIfNewer(libPath) + binary['POSTLINKFLAGS'].append(libPath) + files = [ 'AdminCache.cpp', 'ExtensionSys.cpp', @@ -49,7 +76,6 @@ for i in SM.sdkInfo: 'CoreConfig.cpp', 'Logger.cpp', 'PluginInfoDatabase.cpp', - 'smn_bitbuffer.cpp', 'smn_halflife.cpp', 'PluginSys.cpp', 'smn_console.cpp', @@ -71,7 +97,22 @@ for i in SM.sdkInfo: 'sm_srvcmds.cpp', 'ConsoleDetours.cpp' ] + + if i == 'csgo': + files.append('smn_protobuf.cpp') + else: + files.append('smn_bitbuffer.cpp') + binary.AddSourceFiles('core', files) + + if i == 'csgo': + files = [ + os.path.join('public', 'engine', 'protobuf', 'netmessages.pb.cc'), + os.path.join('public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'), + os.path.join('public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'), + ] + binary.AddSourceFiles(AMBuild.cache[sdk['sdk']], files) + SM.PostSetupHL2Job(extension, binary, i) SM.AutoVersion('core', binary) binary.SendToJob() diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index eb09b749..34a37c7e 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -42,6 +42,10 @@ #include "logic_bridge.h" #include +#if SOURCE_ENGINE == SE_CSGO +#include +#endif + typedef ICommandLine *(*FakeGetCommandLine)(); @@ -487,7 +491,9 @@ void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset) bool CHalfLife2::TextMsg(int client, int dest, const char *msg) { +#if SOURCE_ENGINE != SE_CSGO bf_write *pBitBuf = NULL; +#endif cell_t players[] = {client}; if (dest == HUD_PRINTTALK) @@ -500,7 +506,18 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg) char buffer[192]; UTIL_Format(buffer, sizeof(buffer), "%s\1\n", msg); - if ((pBitBuf = g_UserMsgs.StartMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) +#if SOURCE_ENGINE == SE_CSGO + CCSUsrMsg_SayText *pMsg; + if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) + { + return false; + } + + pMsg->set_ent_idx(0); + pMsg->set_text(buffer); + pMsg->set_chat(false); +#else + if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) { return false; } @@ -508,6 +525,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg) pBitBuf->WriteByte(0); pBitBuf->WriteString(buffer); pBitBuf->WriteByte(1); +#endif g_UserMsgs.EndMessage(); @@ -515,13 +533,29 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg) } } - if ((pBitBuf = g_UserMsgs.StartMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) +#if SOURCE_ENGINE == SE_CSGO + CCSUsrMsg_TextMsg *pMsg; + if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) + { + return false; + } + + // Client tries to read all 5 'params' and will crash if less + pMsg->set_msg_dst(dest); + pMsg->add_params(msg); + pMsg->add_params(""); + pMsg->add_params(""); + pMsg->add_params(""); + pMsg->add_params(""); +#else + if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) { return false; } pBitBuf->WriteByte(dest); pBitBuf->WriteString(msg); +#endif g_UserMsgs.EndMessage(); @@ -530,10 +564,20 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg) bool CHalfLife2::HintTextMsg(int client, const char *msg) { - bf_write *pBitBuf = NULL; cell_t players[] = {client}; - if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) +#if SOURCE_ENGINE == SE_CSGO + CCSUsrMsg_HintText *pMsg; + if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) + { + return false; + } + + pMsg->set_text(msg); +#else + bf_write *pBitBuf = NULL; + + if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) { return false; } @@ -544,6 +588,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg) pBitBuf->WriteByte(1); } pBitBuf->WriteString(msg); +#endif g_UserMsgs.EndMessage(); return true; @@ -551,9 +596,18 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg) bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg) { +#if SOURCE_ENGINE == SE_CSGO + CCSUsrMsg_HintText *pMsg; + if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL) + { + return false; + } + + pMsg->set_text(msg); +#else bf_write *pBitBuf = NULL; - if ((pBitBuf = g_UserMsgs.StartMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL) + if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL) { return false; } @@ -564,6 +618,8 @@ bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg) pBitBuf->WriteByte(1); } pBitBuf->WriteString(msg); +#endif + g_UserMsgs.EndMessage(); return true; @@ -571,15 +627,23 @@ bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg) bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show) { - bf_write *pBitBuf = NULL; KeyValues *SubKey = NULL; int count = 0; cell_t players[] = {client}; - if ((pBitBuf = g_UserMsgs.StartMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL) +#if SOURCE_ENGINE == SE_CSGO + CCSUsrMsg_VGUIMenu *pMsg; + if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL) { return false; } +#else + bf_write *pBitBuf = NULL; + if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL) + { + return false; + } +#endif if (data) { @@ -592,6 +656,18 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo SubKey = data->GetFirstSubKey(); } +#if SOURCE_ENGINE == SE_CSGO + pMsg->set_name(name); + pMsg->set_show(show); + + while (SubKey) + { + CCSUsrMsg_VGUIMenu_Subkey *key = pMsg->add_subkeys(); + key->set_name(SubKey->GetName()); + key->set_str(SubKey->GetString()); + SubKey = SubKey->GetNextKey(); + } +#else pBitBuf->WriteString(name); pBitBuf->WriteByte((show) ? 1 : 0); pBitBuf->WriteByte(count); @@ -601,6 +677,8 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo pBitBuf->WriteString(SubKey->GetString()); SubKey = SubKey->GetNextKey(); } +#endif + g_UserMsgs.EndMessage(); return true; diff --git a/core/MenuStyle_Radio.cpp b/core/MenuStyle_Radio.cpp index e8864560..bbfb1576 100644 --- a/core/MenuStyle_Radio.cpp +++ b/core/MenuStyle_Radio.cpp @@ -39,6 +39,14 @@ #endif #include "logic_bridge.h" +#ifdef USE_PROTOBUF_USERMESSAGES +#include +#endif + +#if SOURCE_ENGINE == SE_CSGO +#include +#endif + extern const char *g_RadioNumTable[]; CRadioStyle g_RadioMenuStyle; int g_ShowMenuId = -1; @@ -155,13 +163,22 @@ static unsigned int g_last_holdtime = 0; static unsigned int g_last_client_count = 0; static int g_last_clients[256]; +#ifdef USE_PROTOBUF_USERMESSAGES +void CRadioStyle::OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFilter *pFilter) +#else void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) +#endif { int count = pFilter->GetRecipientCount(); + +#ifdef USE_PROTOBUF_USERMESSAGES + int c = ((CCSUsrMsg_ShowMenu &)msg).display_time(); +#else bf_read br(bf->GetBasePointer(), 3); br.ReadWord(); int c = br.ReadChar(); +#endif g_last_holdtime = (c == -1) ? 0 : (unsigned)c; @@ -472,6 +489,15 @@ void CRadioMenuPlayer::Radio_Refresh() time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime); } +#ifdef USE_PROTOBUF_USERMESSAGES + // If or when we need to support multiple games per engine with this, we can switch to reflection + // TODO: find what happens past 240 on CS:GO + CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS); + msg->set_bits_valid_slots(display_keys); + msg->set_display_time(time); + msg->set_menu_string(ptr); + g_UserMsgs.EndMessage(); +#else while (true) { if (len > 240) @@ -479,7 +505,8 @@ void CRadioMenuPlayer::Radio_Refresh() save = ptr[240]; ptr[240] = '\0'; } - bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS); + + bf_write *buffer = g_UserMsgs.StartBitBufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS); buffer->WriteWord(display_keys); buffer->WriteChar(time ? time : -1); buffer->WriteByte( (len > 240) ? 1 : 0 ); @@ -496,6 +523,7 @@ void CRadioMenuPlayer::Radio_Refresh() break; } } +#endif display_last_refresh = gpGlobals->curtime; } diff --git a/core/MenuStyle_Radio.h b/core/MenuStyle_Radio.h index 29349814..ec7b99bb 100644 --- a/core/MenuStyle_Radio.h +++ b/core/MenuStyle_Radio.h @@ -37,7 +37,7 @@ #include "MenuStyle_Base.h" #include "sourcemm_api.h" #include -#include +#include "UserMessages.h" #include "sm_fastlink.h" #include #include @@ -65,7 +65,11 @@ private: class CRadioStyle : public BaseMenuStyle, public SMGlobalClass, - public IUserMessageListener +#ifdef USE_PROTOBUF_USERMESSAGES + public IProtobufUserMessageListener +#else + public IBitBufUserMessageListener +#endif { public: CRadioStyle(); @@ -84,7 +88,11 @@ public: //IMenuStyle unsigned int GetMaxPageItems(); unsigned int GetApproxMemUsage(); public: //IUserMessageListener +#ifdef USE_PROTOBUF_USERMESSAGES + void OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFilter *pFilter); +#else void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); +#endif void OnUserMessageSent(int msg_id); public: bool IsSupported(); diff --git a/core/UserMessagePBHelpers.h b/core/UserMessagePBHelpers.h new file mode 100644 index 00000000..7ab47c30 --- /dev/null +++ b/core/UserMessagePBHelpers.h @@ -0,0 +1,853 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod + * Copyright (C) 2013 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_SMPBMESSAGE_H_ +#define _INCLUDE_SOURCEMOD_SMPBMESSAGE_H_ + +#include +#include + +#define GETCHECK_FIELD() \ + const protobuf::FieldDescriptor *field = msg->GetDescriptor()->FindFieldByName(pszFieldName); \ + if (!field) \ + { \ + return false; \ + } + +#define CHECK_FIELD_TYPE(type) \ + if (field->cpp_type() != protobuf::FieldDescriptor::CPPTYPE_##type) \ + { \ + return false; \ + } + +#define CHECK_FIELD_TYPE2(type1, type2) \ + protobuf::FieldDescriptor::CppType fieldType = field->cpp_type(); \ + if (fieldType != protobuf::FieldDescriptor::CPPTYPE_##type1 \ + && fieldType != protobuf::FieldDescriptor::CPPTYPE_##type2) \ + { \ + return false; \ + } + +#define CHECK_FIELD_REPEATED() \ + if (field->label() != protobuf::FieldDescriptor::LABEL_REPEATED) \ + { \ + return false; \ + } + +#define CHECK_FIELD_NOT_REPEATED() \ + if (field->label() == protobuf::FieldDescriptor::LABEL_REPEATED) \ + { \ + return false; \ + } + +#define CHECK_REPEATED_ELEMENT(idx) \ + int elemCount = msg->GetReflection()->FieldSize(*msg, field); \ + if (elemCount == 0 || idx >= elemCount || idx <= 0) \ + { \ + return false; \ + } + +typedef List PBHandleList; + +class SMProtobufMessage +{ +public: + SMProtobufMessage( protobuf::Message *message ) + { + msg = message; + } + + ~SMProtobufMessage() + { + PBHandleList::iterator iter = childHandles.begin(); + while (iter != childHandles.end()) + { + Handle_t &hndl = (*iter); + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + g_HandleSys.FreeHandle(hndl, &sec); + iter = childHandles.erase(iter); + } + } + + inline void AddChildHandle(Handle_t hndl) + { + childHandles.push_back(hndl); + } + + inline protobuf::Message *GetProtobufMessage() + { + return msg; + } + + inline bool GetInt32(const char *pszFieldName, int32 *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(INT32); + CHECK_FIELD_NOT_REPEATED(); + + *out = msg->GetReflection()->GetInt32(*msg, field); + return true; + } + + inline bool SetInt32(const char *pszFieldName, int32 value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(INT32); + CHECK_FIELD_NOT_REPEATED(); + + msg->GetReflection()->SetInt32(msg, field, value); + return true; + } + + inline bool GetRepeatedInt32(const char *pszFieldName, int index, int32 *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(INT32); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + *out = msg->GetReflection()->GetRepeatedInt32(*msg, field, index); + return true; + } + + inline bool AddInt32(const char *pszFieldName, int32 value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(INT32); + CHECK_FIELD_REPEATED(); + + msg->GetReflection()->AddInt32(msg, field, value); + return true; + } + + inline bool GetInt64(const char *pszFieldName, int64 *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(INT64); + CHECK_FIELD_NOT_REPEATED(); + + *out = msg->GetReflection()->GetInt64(*msg, field); + return true; + } + + inline bool SetInt64(const char *pszFieldName, int64 value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(INT64); + CHECK_FIELD_NOT_REPEATED(); + + msg->GetReflection()->SetInt64(msg, field, value); + return true; + } + + inline bool GetRepeatedInt64(const char *pszFieldName, int index, int64 *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(INT64); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + *out = msg->GetReflection()->GetRepeatedInt64(*msg, field, index); + return true; + } + + inline bool AddInt64(const char *pszFieldName, int64 value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(INT64); + CHECK_FIELD_REPEATED(); + + msg->GetReflection()->AddInt64(msg, field, value); + return true; + } + + inline bool GetUInt32(const char *pszFieldName, uint32 *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(UINT32); + CHECK_FIELD_NOT_REPEATED(); + + *out = msg->GetReflection()->GetUInt32(*msg, field); + return true; + } + + inline bool SetUInt32(const char *pszFieldName, uint32 value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(UINT32); + CHECK_FIELD_NOT_REPEATED(); + + msg->GetReflection()->SetUInt32(msg, field, value); + return true; + } + + inline bool GetRepeatedUInt32(const char *pszFieldName, int index, uint32 *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(UINT32); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + *out = msg->GetReflection()->GetRepeatedUInt32(*msg, field, index); + return true; + } + + inline bool AddUInt32(const char *pszFieldName, uint32 value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(UINT32); + CHECK_FIELD_REPEATED(); + + msg->GetReflection()->AddUInt32(msg, field, value); + return true; + } + + inline bool GetUInt64(const char *pszFieldName, uint64 *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(UINT64); + CHECK_FIELD_NOT_REPEATED(); + + *out = msg->GetReflection()->GetUInt64(*msg, field); + return true; + } + + inline bool SetUInt64(const char *pszFieldName, uint64 value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(UINT64); + CHECK_FIELD_NOT_REPEATED(); + + msg->GetReflection()->SetUInt64(msg, field, value); + return true; + } + + inline bool GetRepeatedUInt64(const char *pszFieldName, int index, uint64 *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(UINT64); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + *out = msg->GetReflection()->GetRepeatedUInt64(*msg, field, index); + return true; + } + + inline bool AddUInt64(const char *pszFieldName, uint64 value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(UINT64); + CHECK_FIELD_REPEATED(); + + msg->GetReflection()->AddUInt32(msg, field, value); + return true; + } + + inline bool GetInt32OrUnsigned(const char *pszFieldName, int32 *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE2(INT32, UINT32); + CHECK_FIELD_NOT_REPEATED(); + + if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT32) + *out = (int32)msg->GetReflection()->GetUInt32(*msg, field); + else + *out = msg->GetReflection()->GetInt32(*msg, field); + + return true; + } + + inline bool SetInt32OrUnsigned(const char *pszFieldName, int32 value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE2(INT32, UINT32); + CHECK_FIELD_NOT_REPEATED(); + + if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT32) + msg->GetReflection()->SetUInt32(msg, field, (uint32)value); + else + msg->GetReflection()->SetInt32(msg, field, value); + + return true; + } + + inline bool GetRepeatedInt32OrUnsigned(const char *pszFieldName, int index, int32 *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE2(INT32, UINT32); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT32) + *out = (int32)msg->GetReflection()->GetRepeatedUInt32(*msg, field, index); + else + *out = msg->GetReflection()->GetRepeatedInt32(*msg, field, index); + + return true; + } + + inline bool AddInt32OrUnsigned(const char *pszFieldName, int32 value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE2(INT32, UINT32); + CHECK_FIELD_REPEATED(); + + if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT32) + msg->GetReflection()->AddUInt32(msg, field, (uint32)value); + else + msg->GetReflection()->AddInt32(msg, field, value); + + return true; + } + + inline bool GetBool(const char *pszFieldName, bool *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(BOOL); + CHECK_FIELD_NOT_REPEATED(); + + *out = msg->GetReflection()->GetBool(*msg, field); + return true; + } + + inline bool SetBool(const char *pszFieldName, bool value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(BOOL); + CHECK_FIELD_NOT_REPEATED(); + + msg->GetReflection()->SetBool(msg, field, value); + return true; + } + + inline bool GetRepeatedBool(const char *pszFieldName, int index, bool *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(BOOL); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + *out = msg->GetReflection()->GetRepeatedBool(*msg, field, index); + return true; + } + + inline bool AddBool(const char *pszFieldName, bool value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(BOOL); + CHECK_FIELD_REPEATED(); + + msg->GetReflection()->AddBool(msg, field, value); + return true; + } + + inline bool GetFloat(const char *pszFieldName, float *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(FLOAT); + CHECK_FIELD_NOT_REPEATED(); + + *out = msg->GetReflection()->GetFloat(*msg, field); + return true; + } + + inline bool SetFloat(const char *pszFieldName, float value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(FLOAT); + CHECK_FIELD_NOT_REPEATED(); + + msg->GetReflection()->SetFloat(msg, field, value); + return true; + } + + inline bool GetRepeatedFloat(const char *pszFieldName, int index, float *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(FLOAT); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + *out = msg->GetReflection()->GetRepeatedFloat(*msg, field, index); + return true; + } + + inline bool AddFloat(const char *pszFieldName, float value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(FLOAT); + CHECK_FIELD_REPEATED(); + + msg->GetReflection()->AddFloat(msg, field, value); + return true; + } + + inline bool GetDouble(const char *pszFieldName, double *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(DOUBLE); + CHECK_FIELD_NOT_REPEATED(); + + *out = msg->GetReflection()->GetDouble(*msg, field); + return true; + } + + inline bool SetDouble(const char *pszFieldName, double value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(DOUBLE); + CHECK_FIELD_NOT_REPEATED(); + + msg->GetReflection()->SetDouble(msg, field, value); + return true; + } + + inline bool GetRepeatedDouble(const char *pszFieldName, int index, double *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(DOUBLE); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + *out = msg->GetReflection()->GetRepeatedDouble(*msg, field, index); + return true; + } + + inline bool AddDouble(const char *pszFieldName, double value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(DOUBLE); + CHECK_FIELD_REPEATED(); + + msg->GetReflection()->AddDouble(msg, field, value); + return true; + } + + inline bool GetFloatOrDouble(const char *pszFieldName, float *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE2(FLOAT, DOUBLE); + CHECK_FIELD_NOT_REPEATED(); + + if (fieldType == protobuf::FieldDescriptor::CPPTYPE_DOUBLE) + *out = (float)msg->GetReflection()->GetDouble(*msg, field); + else + *out = msg->GetReflection()->GetFloat(*msg, field); + + return true; + } + + inline bool SetFloatOrDouble(const char *pszFieldName, float value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE2(FLOAT, DOUBLE); + CHECK_FIELD_NOT_REPEATED(); + + if (fieldType == protobuf::FieldDescriptor::CPPTYPE_DOUBLE) + msg->GetReflection()->SetDouble(msg, field, (double)value); + else + msg->GetReflection()->SetFloat(msg, field, value); + + return true; + } + + inline bool GetRepeatedFloatOrDouble(const char *pszFieldName, int index, float *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE2(FLOAT, DOUBLE); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + if (fieldType == protobuf::FieldDescriptor::CPPTYPE_DOUBLE) + *out = (float)msg->GetReflection()->GetRepeatedDouble(*msg, field, index); + else + *out = msg->GetReflection()->GetRepeatedFloat(*msg, field, index); + + return true; + } + + inline bool AddFloatOrDouble(const char *pszFieldName, float value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE2(FLOAT, DOUBLE); + CHECK_FIELD_REPEATED(); + + if (fieldType == protobuf::FieldDescriptor::CPPTYPE_DOUBLE) + msg->GetReflection()->AddDouble(msg, field, (double)value); + else + msg->GetReflection()->AddFloat(msg, field, value); + + return true; + } + + inline bool GetString(const char *pszFieldName, char *out, int size) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(STRING); + CHECK_FIELD_NOT_REPEATED(); + + std::string scratch; + strncopy(out, msg->GetReflection()->GetStringReference(*msg, field, &buffer).c_str(), size); + + return true; + } + + inline bool SetString(const char *pszFieldName, const char *value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(STRING); + CHECK_FIELD_NOT_REPEATED(); + + msg->GetReflection()->SetString(msg, field, value); + return true; + } + + inline bool GetRepeatedString(const char *pszFieldName, int index, char *out, int size) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(STRING); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + std::string scratch; + strncopy(out, msg->GetReflection()->GetRepeatedStringReference(*msg, field, index, &scratch).c_str(), size); + + return true; + } + + inline bool AddString(const char *pszFieldName, const char *value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(STRING); + CHECK_FIELD_REPEATED(); + + msg->GetReflection()->AddString(msg, field, value); + return true; + } + + inline bool GetColor(const char *pszFieldName, Color *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_NOT_REPEATED(); + + const CMsgRGBA &msgRGBA = (const CMsgRGBA &)msg->GetReflection()->GetMessage(*msg, field); + out->SetColor( + msgRGBA.r(), + msgRGBA.g(), + msgRGBA.b(), + msgRGBA.a() + ); + + return true; + } + + inline bool SetColor(const char *pszFieldName, const Color &value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_NOT_REPEATED(); + + CMsgRGBA *msgRGBA = (CMsgRGBA *)msg->GetReflection()->MutableMessage(msg, field); + msgRGBA->set_r(value.r()); + msgRGBA->set_g(value.g()); + msgRGBA->set_b(value.b()); + msgRGBA->set_a(value.a()); + + return true; + } + + inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + const CMsgRGBA &msgRGBA = (const CMsgRGBA &)msg->GetReflection()->GetRepeatedMessage(*msg, field, index); + out->SetColor( + msgRGBA.r(), + msgRGBA.g(), + msgRGBA.b(), + msgRGBA.a() + ); + + return true; + } + + inline bool AddColor(const char *pszFieldName, const Color &value) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_REPEATED(); + + CMsgRGBA *msgRGBA = (CMsgRGBA *)msg->GetReflection()->AddMessage(msg, field); + msgRGBA->set_r(value.r()); + msgRGBA->set_g(value.g()); + msgRGBA->set_b(value.b()); + msgRGBA->set_a(value.a()); + + return true; + } + + inline bool GetVector2D(const char *pszFieldName, Vector2D *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_NOT_REPEATED(); + + const CMsgVector2D &msgVec2d = (const CMsgVector2D &)msg->GetReflection()->GetMessage(*msg, field); + out->Init( + msgVec2d.x(), + msgVec2d.y() + ); + + return true; + } + + inline bool SetVector2D(const char *pszFieldName, Vector2D &vec) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_NOT_REPEATED(); + + CMsgVector2D *msgVec2d = (CMsgVector2D *)msg->GetReflection()->MutableMessage(msg, field); + msgVec2d->set_x(vec.x); + msgVec2d->set_y(vec.y); + + return true; + } + + inline bool GetRepeatedVector2D(const char *pszFieldName, int index, Vector2D *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + const CMsgVector2D &msgVec2d = (const CMsgVector2D &)msg->GetReflection()->GetRepeatedMessage(*msg, field, index); + out->Init( + msgVec2d.x(), + msgVec2d.y() + ); + + return true; + } + + inline bool AddVector2D(const char *pszFieldName, Vector2D &vec) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_REPEATED(); + + CMsgVector2D *msgVec2d = (CMsgVector2D *)msg->GetReflection()->AddMessage(msg, field); + msgVec2d->set_x(vec.x); + msgVec2d->set_y(vec.y); + + return true; + } + + inline bool GetVector(const char *pszFieldName, Vector *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_NOT_REPEATED(); + + const CMsgVector &msgVec = (const CMsgVector &)msg->GetReflection()->GetMessage(*msg, field); + out->Init( + msgVec.x(), + msgVec.y(), + msgVec.z() + ); + + return true; + } + + inline bool SetVector(const char *pszFieldName, Vector &vec) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_NOT_REPEATED(); + + CMsgVector *msgVec = (CMsgVector *)msg->GetReflection()->MutableMessage(msg, field); + msgVec->set_x(vec.x); + msgVec->set_y(vec.y); + msgVec->set_z(vec.z); + + return true; + } + + inline bool GetRepeatedVector(const char *pszFieldName, int index, Vector *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + const CMsgVector &msgVec = (const CMsgVector &)msg->GetReflection()->GetRepeatedMessage(*msg, field, index); + out->Init( + msgVec.x(), + msgVec.y(), + msgVec.z() + ); + + return true; + } + + inline bool AddVector(const char *pszFieldName, Vector &vec) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_REPEATED(); + + CMsgVector *msgVec = (CMsgVector *)msg->GetReflection()->AddMessage(msg, field); + msgVec->set_x(vec.x); + msgVec->set_y(vec.y); + msgVec->set_z(vec.z); + + return true; + } + + inline bool GetQAngle(const char *pszFieldName, QAngle *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_NOT_REPEATED(); + + const CMsgQAngle &msgAng = (const CMsgQAngle &)msg->GetReflection()->GetMessage(*msg, field); + out->Init( + msgAng.x(), + msgAng.y(), + msgAng.z() + ); + + return true; + } + + inline bool SetQAngle(const char *pszFieldName, QAngle &vec) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_NOT_REPEATED(); + + CMsgQAngle *msgAng = (CMsgQAngle *)msg->GetReflection()->MutableMessage(msg, field); + msgAng->set_x(vec.x); + msgAng->set_y(vec.y); + msgAng->set_z(vec.z); + + return true; + } + + inline bool GetRepeatedQAngle(const char *pszFieldName, int index, QAngle *out) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + const CMsgQAngle &msgAng = (const CMsgQAngle &)msg->GetReflection()->GetRepeatedMessage(*msg, field, index); + out->Init( + msgAng.x(), + msgAng.y(), + msgAng.z() + ); + + return true; + } + + inline bool AddQAngle(const char *pszFieldName, QAngle &vec) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_REPEATED(); + + CMsgQAngle *msgAng = (CMsgQAngle *)msg->GetReflection()->AddMessage(msg, field); + msgAng->set_x(vec.x); + msgAng->set_y(vec.y); + msgAng->set_z(vec.z); + + return true; + } + + inline bool GetMessage(const char *pszFieldName, protobuf::Message **message) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_NOT_REPEATED(); + + *message = msg->GetReflection()->MutableMessage(msg, field); + + return true; + } + + inline bool GetRepeatedMessage(const char *pszFieldName, int index, const protobuf::Message **message) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_REPEATED(); + CHECK_REPEATED_ELEMENT(index); + + const protobuf::Message *m = &msg->GetReflection()->GetRepeatedMessage(*msg, field, index); + *message = m; + + return true; + } + + inline bool AddMessage(const char *pszFieldName, protobuf::Message **message) + { + GETCHECK_FIELD(); + CHECK_FIELD_TYPE(MESSAGE); + CHECK_FIELD_REPEATED(); + + *message = msg->GetReflection()->AddMessage(msg, field); + + return true; + } + + inline int GetRepeatedFieldCount(const char *pszFieldName) + { + const protobuf::FieldDescriptor *field = msg->GetDescriptor()->FindFieldByName(pszFieldName); \ + if (!field) + return -1; + + if (field->label() != protobuf::FieldDescriptor::LABEL_REPEATED) + return -1; + + return msg->GetReflection()->FieldSize(*msg, field); + } + +private: + protobuf::Message *msg; + PBHandleList childHandles; +}; + +#endif // _INCLUDE_SOURCEMOD_SMPBMESSAGE_H_ diff --git a/core/UserMessages.cpp b/core/UserMessages.cpp index 5f4738c6..72e8b315 100644 --- a/core/UserMessages.cpp +++ b/core/UserMessages.cpp @@ -32,18 +32,32 @@ #include "UserMessages.h" #include "sm_stringutil.h" +#if SOURCE_ENGINE == SE_CSGO +#include +#endif + UserMessages g_UserMsgs; +#if SOURCE_ENGINE == SE_CSGO +SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &); +#else #if SOURCE_ENGINE >= SE_LEFT4DEAD SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int, const char *); #else SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int); #endif SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0); +#endif // ==SE_CSGO -UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500) +UserMessages::UserMessages() +#ifndef USE_PROTOBUF_USERMESSAGES + : m_InterceptBuffer(m_pBase, 2500) { m_Names = sm_trie_create(); +#else + : m_InterceptBuffer(NULL) +{ +#endif m_HookCount = 0; m_InExec = false; m_InHook = false; @@ -53,7 +67,9 @@ UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500) UserMessages::~UserMessages() { +#ifndef USE_PROTOBUF_USERMESSAGES sm_trie_destroy(m_Names); +#endif CStack::iterator iter; for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++) @@ -65,8 +81,10 @@ UserMessages::~UserMessages() void UserMessages::OnSourceModStartup(bool late) { +#ifndef USE_PROTOBUF_USERMESSAGES /* -1 means SourceMM was unable to get the user message list */ m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1); +#endif } void UserMessages::OnSourceModAllInitialized() @@ -78,16 +96,25 @@ void UserMessages::OnSourceModAllShutdown() { if (m_HookCount) { +#if SOURCE_ENGINE == SE_CSGO + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true); +#else SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false); SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true); SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false); SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true); +#endif } m_HookCount = 0; } int UserMessages::GetMessageIndex(const char *msg) { +#if SOURCE_ENGINE == SE_CSGO + // Can split this per engine and/or game later + return g_Cstrike15UsermessageHelpers.GetIndex(msg); +#else int msgid; if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast(&msgid))) @@ -118,10 +145,19 @@ int UserMessages::GetMessageIndex(const char *msg) } return msgid; +#endif } bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const { +#if SOURCE_ENGINE == SE_CSGO + const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid); + if (!pszName) + return false; + + strncopy(buffer, pszName, maxlength); + return true; +#else if (m_FallbackSearch) { int size; @@ -137,10 +173,14 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con } return false; +#endif } -bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags) +bf_write *UserMessages::StartBitBufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags) { +#ifdef USE_PROTOBUF_USERMESSAGES + return NULL; +#else bf_write *buffer; if (m_InExec || m_InHook) @@ -182,6 +222,68 @@ bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigne } return buffer; +#endif // USE_PROTOBUF_USERMESSAGES +} + +google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags) +{ +#ifndef USE_PROTOBUF_USERMESSAGES + return NULL; +#else + protobuf::Message *buffer; + + if (m_InExec || m_InHook) + { + return NULL; + } + if (msg_id < 0 || msg_id >= 255) + { + return NULL; + } + + m_CurId = msg_id; + m_CellRecFilter.Initialize(players, playersNum); + + m_CurFlags = flags; + if (m_CurFlags & USERMSG_INITMSG) + { + m_CellRecFilter.SetToInit(true); + } + if (m_CurFlags & USERMSG_RELIABLE) + { + m_CellRecFilter.SetToReliable(true); + } + + m_InExec = true; + + if (m_CurFlags & USERMSG_BLOCKHOOKS) + { + // direct message creation, return buffer "from engine". keep track + m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New(); + buffer = m_FakeEngineBuffer; + } else { + protobuf::Message *msg = OnStartMessage_Pre(static_cast(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id)); + switch (m_FakeMetaRes) + { + case MRES_IGNORED: + case MRES_HANDLED: + m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New(); + buffer = m_FakeEngineBuffer; + break; + + case MRES_OVERRIDE: + m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New(); + // fallthrough + case MRES_SUPERCEDE: + buffer = msg; + break; + } + + OnStartMessage_Post(static_cast(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id)); + } + + return buffer; +#endif // USE_PROTOBUF_USERMESSAGES } bool UserMessages::EndMessage() @@ -191,12 +293,37 @@ bool UserMessages::EndMessage() return false; } +#if SOURCE_ENGINE == SE_CSGO + if (m_CurFlags & USERMSG_BLOCKHOOKS) + { + ENGINE_CALL(SendUserMessage)(static_cast(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer); + delete m_FakeEngineBuffer; + m_FakeEngineBuffer = NULL; + } else { + OnMessageEnd_Pre(); + + switch (m_FakeMetaRes) + { + case MRES_IGNORED: + case MRES_HANDLED: + case MRES_OVERRIDE: + engine->SendUserMessage(static_cast(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer); + delete m_FakeEngineBuffer; + m_FakeEngineBuffer = NULL; + break; + //case MRES_SUPERCEDE: + } + + OnMessageEnd_Post(); + } +#else if (m_CurFlags & USERMSG_BLOCKHOOKS) { ENGINE_CALL(MessageEnd)(); } else { engine->MessageEnd(); } +#endif // SE_CSGO m_InExec = false; m_CurFlags = 0; @@ -205,31 +332,60 @@ bool UserMessages::EndMessage() return true; } +UserMessageType UserMessages::GetUserMessageType() const +{ +#ifdef USE_PROTOBUF_USERMESSAGES + return UM_Protobuf; +#else + return UM_BitBuf; +#endif +} + bool UserMessages::HookUserMessage2(int msg_id, IUserMessageListener *pListener, bool intercept) { - return InternalHook(msg_id, pListener, intercept, true); +#ifdef USE_PROTOBUF_USERMESSAGES + return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true); +#else + return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true); +#endif } bool UserMessages::UnhookUserMessage2(int msg_id, IUserMessageListener *pListener, bool intercept) { - return InternalUnhook(msg_id, pListener, intercept, true); +#ifdef USE_PROTOBUF_USERMESSAGES + return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true); +#else + return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true); +#endif } bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) { - return InternalHook(msg_id, pListener, intercept, false); +#ifdef USE_PROTOBUF_USERMESSAGES + return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false); +#else + return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false); +#endif } bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept) { - return InternalUnhook(msg_id, pListener, intercept, false); +#ifdef USE_PROTOBUF_USERMESSAGES + return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false); +#else + return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false); +#endif } -bool UserMessages::InternalHook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew) +#ifdef USE_PROTOBUF_USERMESSAGES +bool UserMessages::InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew) +#else +bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew) +#endif { if (msg_id < 0 || msg_id >= 255) { @@ -252,10 +408,15 @@ bool UserMessages::InternalHook(int msg_id, IUserMessageListener *pListener, boo if (!m_HookCount++) { +#if SOURCE_ENGINE == SE_CSGO + SH_ADD_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false); + SH_ADD_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true); +#else SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false); SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true); SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false); SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true); +#endif } if (intercept) @@ -268,7 +429,11 @@ bool UserMessages::InternalHook(int msg_id, IUserMessageListener *pListener, boo return true; } -bool UserMessages::InternalUnhook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew) +#ifdef USE_PROTOBUF_USERMESSAGES +bool UserMessages::InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew) +#else +bool UserMessages::InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew) +#endif { MsgList *pList; MsgIter iter; @@ -309,14 +474,167 @@ void UserMessages::_DecRefCounter() { if (--m_HookCount == 0) { +#if SOURCE_ENGINE == SE_CSGO + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false); + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true); +#else SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false); SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true); SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false); SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true); +#endif } } -#if SOURCE_ENGINE >= SE_LEFT4DEAD +#ifdef USE_PROTOBUF_USERMESSAGES +// Unlike protobuf's Message::CopyFrom: +// - Does not require to/from message descriptors to be identical. +// - Fields are copied by name, rather than index. +// - String fields are retrieved for copy with GetStringReference, to avoid destucting libprotobuf std::string in sm. +// - Unknown fields in |from| message are not copied to |to| message. +// - Copying Message fields recursively calls this function, rather than Message::MergeFrom. +static void _CopyProtobufMessage(const protobuf::Message &from, protobuf::Message *to) +{ + const protobuf::Descriptor* descriptor = from.GetDescriptor(); + + const protobuf::Reflection* from_reflection = from.GetReflection(); + const protobuf::Reflection* to_reflection = to->GetReflection(); + + protobuf::UnknownFieldSet toUnknownFields; + + int fromFieldCount = descriptor->field_count(); + for (int i = 0; i < fromFieldCount; i++) + { + const protobuf::FieldDescriptor* fromField = descriptor->field(i); + const protobuf::FieldDescriptor* toField = to->GetDescriptor()->FindFieldByName(fromField->name()); + + // This will stripped new fields off of intercepted usermessages. + // TODO: fix that. + if (!toField) + { + continue; + } + + if (fromField->is_repeated()) + { + int count = from_reflection->FieldSize(from, fromField); + for (int j = 0; j < count; j++) + { + switch (fromField->cpp_type()) + { +#define HANDLE_TYPE(CPPTYPE, METHOD) \ + case protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: \ + to_reflection->Add##METHOD(to, toField, \ + from_reflection->GetRepeated##METHOD(from, fromField, j)); \ + break; + HANDLE_TYPE(INT32 , Int32 ); + HANDLE_TYPE(INT64 , Int64 ); + HANDLE_TYPE(UINT32, UInt32); + HANDLE_TYPE(UINT64, UInt64); + HANDLE_TYPE(FLOAT , Float ); + HANDLE_TYPE(DOUBLE, Double); + HANDLE_TYPE(BOOL , Bool ); + HANDLE_TYPE(ENUM , Enum ); +#undef HANDLE_TYPE + case protobuf::FieldDescriptor::CPPTYPE_STRING: + { + std::string buffer; + to_reflection->AddString(to, toField, + from_reflection->GetRepeatedStringReference(from, fromField, j, &buffer)); + } + break; + case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + _CopyProtobufMessage( + from_reflection->GetRepeatedMessage(from, fromField, j), + to_reflection->AddMessage(to, toField) + ); + break; + } + } + } + else + { + switch (fromField->cpp_type()) + { +#define HANDLE_TYPE(CPPTYPE, METHOD) \ + case protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: \ + to_reflection->Set##METHOD(to, toField, \ + from_reflection->Get##METHOD(from, fromField)); \ + break; + HANDLE_TYPE(INT32 , Int32 ); + HANDLE_TYPE(INT64 , Int64 ); + HANDLE_TYPE(UINT32, UInt32); + HANDLE_TYPE(UINT64, UInt64); + HANDLE_TYPE(FLOAT , Float ); + HANDLE_TYPE(DOUBLE, Double); + HANDLE_TYPE(BOOL , Bool ); + HANDLE_TYPE(ENUM , Enum ); +#undef HANDLE_TYPE + case protobuf::FieldDescriptor::CPPTYPE_STRING: + { + std::string buffer; + to_reflection->SetString(to, toField, + from_reflection->GetStringReference(from, fromField, &buffer)); + } + break; + case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + _CopyProtobufMessage( + from_reflection->GetMessage(from, fromField), + to_reflection->MutableMessage(to, toField) + ); + break; + } + } + } +} +#endif + +#if SOURCE_ENGINE == SE_CSGO +void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg) +{ + OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type)); + if (m_FakeMetaRes == MRES_SUPERCEDE) + { + _CopyProtobufMessage(msg, m_InterceptBuffer); + } + else + { + OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type)); + } + + OnMessageEnd_Pre(); + if (m_FakeMetaRes == MRES_SUPERCEDE) + RETURN_META(MRES_SUPERCEDE); + + RETURN_META(MRES_IGNORED); +} + +void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg) +{ + OnMessageEnd_Post(); + RETURN_META(MRES_IGNORED); +} +#endif + +#ifdef USE_PROTOBUF_USERMESSAGES +#define UM_RETURN_META_VALUE(res, val) \ + m_FakeMetaRes = res; \ + return val; + +#define UM_RETURN_META(res) \ + m_FakeMetaRes = res; \ + return; +#else +#define UM_RETURN_META_VALUE(res, val) \ + RETURN_META_VALUE(res, val) + +#define UM_RETURN_META(res) \ + RETURN_META(res) +#endif + +#if SOURCE_ENGINE == SE_CSGO +protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name) +#elif SOURCE_ENGINE >= SE_LEFT4DEAD bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name) #else bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type) @@ -329,7 +647,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ || (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS))) { m_InHook = false; - RETURN_META_VALUE(MRES_IGNORED, NULL); + UM_RETURN_META_VALUE(MRES_IGNORED, NULL); } m_CurId = msg_type; @@ -339,14 +657,23 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ if (!is_intercept_empty) { +#ifdef USE_PROTOBUF_USERMESSAGES + if (m_InterceptBuffer) + delete m_InterceptBuffer; + m_InterceptBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New(); + UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer); +#else m_InterceptBuffer.Reset(); - RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer); + UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer); +#endif } - RETURN_META_VALUE(MRES_IGNORED, NULL); + UM_RETURN_META_VALUE(MRES_IGNORED, NULL); } -#if SOURCE_ENGINE >= SE_LEFT4DEAD +#if SOURCE_ENGINE == SE_CSGO +protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name) +#elif SOURCE_ENGINE >= SE_LEFT4DEAD bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name) #else bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type) @@ -354,19 +681,24 @@ bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_ty { if (!m_InHook) { - RETURN_META_VALUE(MRES_IGNORED, NULL); + UM_RETURN_META_VALUE(MRES_IGNORED, NULL); } +#ifdef USE_PROTOBUF_USERMESSAGES + m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New(); + m_OrigBuffer = m_FakeEngineBuffer; +#else m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *); +#endif - RETURN_META_VALUE(MRES_IGNORED, NULL); + UM_RETURN_META_VALUE(MRES_IGNORED, NULL); } void UserMessages::OnMessageEnd_Post() { if (!m_InHook) { - RETURN_META(MRES_IGNORED); + UM_RETURN_META(MRES_IGNORED); } MsgList *pList; @@ -434,7 +766,7 @@ void UserMessages::OnMessageEnd_Pre() { if (!m_InHook) { - RETURN_META(MRES_IGNORED); + UM_RETURN_META(MRES_IGNORED); } MsgList *pList; @@ -450,7 +782,11 @@ void UserMessages::OnMessageEnd_Pre() { pInfo = (*iter); pInfo->IsHooked = true; +#ifdef USE_PROTOBUF_USERMESSAGES + res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter); +#else res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter); +#endif intercepted = true; @@ -498,8 +834,12 @@ void UserMessages::OnMessageEnd_Pre() if (!handled && intercepted) { +#if SOURCE_ENGINE == SE_CSGO + ENGINE_CALL(SendUserMessage)(static_cast(*m_CurRecFilter), m_CurId, *m_InterceptBuffer); + delete m_InterceptBuffer; + m_InterceptBuffer = NULL; +#else bf_write *engine_bfw; - #if SOURCE_ENGINE >= SE_LEFT4DEAD engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId)); #else @@ -508,6 +848,7 @@ void UserMessages::OnMessageEnd_Pre() m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten()); engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten()); ENGINE_CALL(MessageEnd)(); +#endif // SE_CSGO } pList = &m_msgHooks[m_CurId]; @@ -529,8 +870,8 @@ void UserMessages::OnMessageEnd_Pre() iter++; } - RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED); + UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED); supercede: m_BlockEndPost = true; - RETURN_META(MRES_SUPERCEDE); + UM_RETURN_META(MRES_SUPERCEDE); } diff --git a/core/UserMessages.h b/core/UserMessages.h index f6c5c197..45fab544 100644 --- a/core/UserMessages.h +++ b/core/UserMessages.h @@ -36,16 +36,35 @@ #include #include "sourcemm_api.h" #include "sm_trie.h" +#include "sm_stringutil.h" #include "CellRecipientFilter.h" using namespace SourceHook; using namespace SourceMod; +#if SOURCE_ENGINE == SE_CSGO +#define USE_PROTOBUF_USERMESSAGES +#endif + +#ifdef USE_PROTOBUF_USERMESSAGES +#include +#include +#include + +using namespace google; +#else +#include +#endif + #define INVALID_MESSAGE_ID -1 struct ListenerInfo { - IUserMessageListener *Callback; +#ifdef USE_PROTOBUF_USERMESSAGES + IProtobufUserMessageListener *Callback; +#else + IBitBufUserMessageListener *Callback; +#endif bool IsHooked; bool KillMe; bool IsNew; @@ -70,7 +89,8 @@ public: //IUserMessages bool GetMessageName(int msgid, char *buffer, size_t maxlength) const; bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false); - bf_write *StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags); + bf_write *StartBitBufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags); + google::protobuf::Message *StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags); bool EndMessage(); bool HookUserMessage2(int msg_id, IUserMessageListener *pListener, @@ -78,8 +98,17 @@ public: //IUserMessages bool UnhookUserMessage2(int msg_id, IUserMessageListener *pListener, bool intercept=false); + UserMessageType GetUserMessageType() const; public: -#if SOURCE_ENGINE >= SE_LEFT4DEAD +#if SOURCE_ENGINE == SE_CSGO + void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg); + void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg); +#endif + +#if SOURCE_ENGINE == SE_CSGO + protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name); + protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name); +#elif SOURCE_ENGINE >= SE_LEFT4DEAD bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name); bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name); #else @@ -89,8 +118,13 @@ public: void OnMessageEnd_Pre(); void OnMessageEnd_Post(); private: - bool InternalHook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew); - bool InternalUnhook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew); +#ifdef USE_PROTOBUF_USERMESSAGES + bool InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew); + bool InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew); +#else + bool InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew); + bool InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew); +#endif void _DecRefCounter(); private: List m_msgHooks[255]; @@ -98,15 +132,26 @@ private: CStack m_FreeListeners; unsigned char m_pBase[2500]; IRecipientFilter *m_CurRecFilter; +#ifndef USE_PROTOBUF_USERMESSAGES bf_write m_InterceptBuffer; bf_write *m_OrigBuffer; bf_read m_ReadBuffer; +#else + // The engine used to provide this. Now we track it. + protobuf::Message *m_OrigBuffer; + protobuf::Message *m_FakeEngineBuffer; + META_RES m_FakeMetaRes; + + protobuf::Message *m_InterceptBuffer; +#endif size_t m_HookCount; bool m_InHook; bool m_BlockEndPost; +#ifndef USE_PROTOBUF_USERMESSAGES bool m_FallbackSearch; Trie *m_Names; +#endif CellRecipientFilter m_CellRecFilter; bool m_InExec; int m_CurFlags; diff --git a/core/smn_bitbuffer.cpp b/core/smn_bitbuffer.cpp index 5ee312b6..15df1b53 100644 --- a/core/smn_bitbuffer.cpp +++ b/core/smn_bitbuffer.cpp @@ -29,11 +29,16 @@ * Version: $Id$ */ +#include "UserMessages.h" + +#ifndef USE_PROTOBUF_USERMESSAGES + #include "sourcemod.h" #include "HandleSys.h" #include #include #include +#include "smn_usermsgs.h" static cell_t smn_BfWriteBool(IPluginContext *pCtx, const cell_t *params) { @@ -713,3 +718,5 @@ REGISTER_NATIVES(bitbufnatives) {"BfGetNumBytesLeft", smn_BfGetNumBytesLeft}, {NULL, NULL} }; + +#endif diff --git a/core/smn_console.cpp b/core/smn_console.cpp index ad87aa69..55bdf0ab 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -48,6 +48,10 @@ #include "ConsoleDetours.h" #include "ConCommandBaseIterator.h" +#if SOURCE_ENGINE == SE_CSGO +#include +#endif + #if SOURCE_ENGINE >= SE_EYE #define NETMSG_BITS 6 #else @@ -1427,10 +1431,22 @@ static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params) char data[256]; bf_write buffer(data, sizeof(data)); +#if SOURCE_ENGINE == SE_CSGO + CNETMsg_SetConVar msg; + CMsg_CVars_CVar *cvar = msg.mutable_convars()->add_cvars(); + + cvar->set_name(pConVar->GetName()); + cvar->set_value(value); + + buffer.WriteVarInt32(net_SetConVar); + buffer.WriteVarInt32(msg.ByteSize()); + msg.SerializeWithCachedSizesToArray( (uint8 *)( buffer.GetBasePointer() + buffer.GetNumBytesWritten() ) ); +#else buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS); buffer.WriteByte(1); buffer.WriteString(pConVar->GetName()); buffer.WriteString(value); +#endif CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]); diff --git a/core/smn_hudtext.cpp b/core/smn_hudtext.cpp index ca1f34a2..37b034e6 100644 --- a/core/smn_hudtext.cpp +++ b/core/smn_hudtext.cpp @@ -37,6 +37,10 @@ #include "HandleSys.h" #include "logic_bridge.h" +#if SOURCE_ENGINE == SE_CSGO +#include +#endif + #define MAX_HUD_CHANNELS 6 int g_HudMsgNum = -1; @@ -308,12 +312,39 @@ static cell_t SetHudTextParamsEx(IPluginContext *pContext, const cell_t *params) void UTIL_SendHudText(int client, const hud_text_parms &textparms, const char *pMessage) { - bf_write *bf; cell_t players[1]; players[0] = client; - bf = g_UserMsgs.StartMessage(g_HudMsgNum, players, 1, 0); +#if SOURCE_ENGINE == SE_CSGO + // If or when we need to support multiple games per engine with this, we can switch to reflection + CCSUsrMsg_HudMsg *msg = (CCSUsrMsg_HudMsg *)g_UserMsgs.StartProtobufMessage(g_HudMsgNum, players, 1, 0); + msg->set_channel(textparms.channel & 0xFF); + + CMsgVector2D *pos = msg->mutable_pos(); + pos->set_x(textparms.x); + pos->set_y(textparms.y); + + CMsgRGBA *color1 = msg->mutable_clr1(); + color1->set_r(textparms.r1); + color1->set_g(textparms.g1); + color1->set_b(textparms.b1); + color1->set_a(textparms.a1); + + CMsgRGBA *color2 = msg->mutable_clr2(); + color2->set_r(textparms.r2); + color2->set_g(textparms.g2); + color2->set_b(textparms.b2); + color2->set_a(textparms.a2); + + msg->set_effect(textparms.effect); + msg->set_fade_in_time(textparms.fadeinTime); + msg->set_fade_out_time(textparms.fadeoutTime); + msg->set_hold_time(textparms.holdTime); + msg->set_fx_time(textparms.fxTime); + msg->set_text(pMessage); +#else + bf_write *bf = g_UserMsgs.StartBitBufMessage(g_HudMsgNum, players, 1, 0); bf->WriteByte(textparms.channel & 0xFF ); bf->WriteFloat(textparms.x); bf->WriteFloat(textparms.y); @@ -331,6 +362,7 @@ void UTIL_SendHudText(int client, const hud_text_parms &textparms, const char *p bf->WriteFloat(textparms.holdTime); bf->WriteFloat(textparms.fxTime); bf->WriteString(pMessage); +#endif g_UserMsgs.EndMessage(); } diff --git a/core/smn_protobuf.cpp b/core/smn_protobuf.cpp new file mode 100644 index 00000000..eb237176 --- /dev/null +++ b/core/smn_protobuf.cpp @@ -0,0 +1,823 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod + * Copyright (C) 2013 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include "UserMessages.h" + +#ifdef USE_PROTOBUF_USERMESSAGES + +#include "HandleSys.h" +#include "UserMessagePBHelpers.h" +#include "smn_usermsgs.h" + +// Assumes pbuf message handle is param 1, gets message as msg +#define GET_MSG_FROM_HANDLE_OR_ERR() \ + Handle_t hndl = static_cast(params[1]); \ + HandleError herr; \ + HandleSecurity sec; \ + SMProtobufMessage *msg; \ + \ + sec.pOwner = NULL; \ + sec.pIdentity = g_pCoreIdent; \ + \ + if ((herr=g_HandleSys.ReadHandle(hndl, g_ProtobufType, &sec, (void **)&msg)) \ + != HandleError_None) \ + { \ + return pCtx->ThrowNativeError("Invalid protobuf message handle %x (error %d)", hndl, herr); \ + } + +// Assumes message field name is param 2, gets as strField +#define GET_FIELD_NAME_OR_ERR() \ + int err; \ + char *strField; \ + if ((err=pCtx->LocalToString(params[2], &strField)) != SP_ERROR_NONE) \ + { \ + pCtx->ThrowNativeErrorEx(err, NULL); \ + return 0; \ + } + +static cell_t smn_PbReadInt(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + int ret; + if (!msg->GetInt32OrUnsigned(strField, &ret)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return ret; +} + +static cell_t smn_PbReadFloat(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + float ret; + if (!msg->GetFloatOrDouble(strField, &ret)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return sp_ftoc(ret); +} + +static cell_t smn_PbReadBool(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + bool ret; + if (!msg->GetBool(strField, &ret)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return ret ? 1 : 0; +} + +static cell_t smn_PbReadString(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + char *buf; + pCtx->LocalToPhysAddr(params[3], (cell_t **)&buf); + + if (!msg->GetString(strField, buf, params[4])) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbReadColor(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *out; + pCtx->LocalToPhysAddr(params[3], &out); + + Color clr; + if (!msg->GetColor(strField, &clr)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + out[0] = clr.r(); + out[1] = clr.g(); + out[2] = clr.b(); + out[3] = clr.a(); + + return 1; +} + +static cell_t smn_PbReadAngle(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *out; + pCtx->LocalToPhysAddr(params[3], &out); + + QAngle ang; + if (!msg->GetQAngle(strField, &ang)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + out[0] = sp_ftoc(ang.x); + out[1] = sp_ftoc(ang.y); + out[2] = sp_ftoc(ang.z); + + return 1; +} + +static cell_t smn_PbReadVector(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *out; + pCtx->LocalToPhysAddr(params[3], &out); + + Vector vec; + if (!msg->GetVector(strField, &vec)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + out[0] = sp_ftoc(vec.x); + out[1] = sp_ftoc(vec.y); + out[2] = sp_ftoc(vec.z); + + return 1; +} + +static cell_t smn_PbReadVector2D(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *out; + pCtx->LocalToPhysAddr(params[3], &out); + + Vector2D vec; + if (!msg->GetVector2D(strField, &vec)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + out[0] = sp_ftoc(vec.x); + out[1] = sp_ftoc(vec.y); + + return 1; +} + +static cell_t smn_PbGetRepeatedFieldCount(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + int cnt = msg->GetRepeatedFieldCount(strField); + if (cnt == -1) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return cnt; +} + +static cell_t smn_PbReadRepeatedInt(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + int ret; + if (!msg->GetRepeatedInt32OrUnsigned(strField, params[3], &ret)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\"[%d] for message \"%s\"", strField, params[3], msg->GetProtobufMessage()->GetTypeName()); + } + + return ret; +} + +static cell_t smn_PbReadRepeatedFloat(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + float ret; + if (!msg->GetRepeatedFloatOrDouble(strField, params[3], &ret)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\"[%d] for message \"%s\"", strField, params[3], msg->GetProtobufMessage()->GetTypeName()); + } + + return sp_ftoc(ret); +} + +static cell_t smn_PbReadRepeatedBool(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + bool ret; + if (!msg->GetRepeatedBool(strField, params[3], &ret)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\"[%d] for message \"%s\"", strField, params[3], msg->GetProtobufMessage()->GetTypeName()); + } + + return ret ? 1 : 0; +} + +static cell_t smn_PbReadRepeatedString(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + char *buf; + pCtx->LocalToPhysAddr(params[4], (cell_t **)&buf); + + if (!msg->GetRepeatedString(strField, params[3], buf, params[5])) + { + return pCtx->ThrowNativeError("Invalid field \"%s\"[%d] for message \"%s\"", strField, params[3], msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbReadRepeatedColor(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *out; + pCtx->LocalToPhysAddr(params[4], &out); + + Color clr; + if (!msg->GetRepeatedColor(strField, params[3], &clr)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\"[%d] for message \"%s\"", strField, params[3], msg->GetProtobufMessage()->GetTypeName()); + } + + out[0] = clr.r(); + out[1] = clr.g(); + out[2] = clr.b(); + out[3] = clr.a(); + + return 1; +} + +static cell_t smn_PbReadRepeatedAngle(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *out; + pCtx->LocalToPhysAddr(params[4], &out); + + QAngle ang; + if (!msg->GetRepeatedQAngle(strField, params[3], &ang)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\"[%d] for message \"%s\"", strField, params[3], msg->GetProtobufMessage()->GetTypeName()); + } + + out[0] = sp_ftoc(ang.x); + out[1] = sp_ftoc(ang.y); + out[2] = sp_ftoc(ang.z); + + return 1; +} + +static cell_t smn_PbReadRepeatedVector(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *out; + pCtx->LocalToPhysAddr(params[4], &out); + + Vector vec; + if (!msg->GetRepeatedVector(strField, params[3], &vec)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\"[%d] for message \"%s\"", strField, params[3], msg->GetProtobufMessage()->GetTypeName()); + } + + out[0] = sp_ftoc(vec.x); + out[1] = sp_ftoc(vec.y); + out[2] = sp_ftoc(vec.z); + + return 1; +} + +static cell_t smn_PbReadRepeatedVector2D(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *out; + pCtx->LocalToPhysAddr(params[4], &out); + + Vector2D vec; + if (!msg->GetRepeatedVector2D(strField, params[3], &vec)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\"[%d] for message \"%s\"", strField, params[3], msg->GetProtobufMessage()->GetTypeName()); + } + + out[0] = sp_ftoc(vec.x); + out[1] = sp_ftoc(vec.y); + + return 1; +} + +static cell_t smn_PbSetInt(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + if (!msg->SetInt32OrUnsigned(strField, params[3])) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbSetFloat(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + if (!msg->SetFloatOrDouble(strField, sp_ctof(params[3]))) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbSetBool(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + bool value = (params[3] == 0 ? false : true); + if (!msg->SetBool(strField, value)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbSetString(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + char *strValue; + if ((err=pCtx->LocalToString(params[3], &strValue)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + if (!msg->SetString(strField, strValue)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbSetColor(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *clrParams; + if ((err=pCtx->LocalToPhysAddr(params[3], &clrParams)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + Color clr( + clrParams[0], + clrParams[1], + clrParams[2], + clrParams[3]); + + if (!msg->SetColor(strField, clr)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbSetAngle(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *angParams; + if ((err=pCtx->LocalToPhysAddr(params[3], &angParams)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + QAngle ang( + sp_ctof(angParams[0]), + sp_ctof(angParams[1]), + sp_ctof(angParams[2])); + + if (!msg->SetQAngle(strField, ang)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbSetVector(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *vecParams; + if ((err=pCtx->LocalToPhysAddr(params[3], &vecParams)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + Vector vec( + sp_ctof(vecParams[0]), + sp_ctof(vecParams[1]), + sp_ctof(vecParams[2])); + + if (!msg->SetVector(strField, vec)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbSetVector2D(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *vecParams; + if ((err=pCtx->LocalToPhysAddr(params[3], &vecParams)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + Vector2D vec( + sp_ctof(vecParams[0]), + sp_ctof(vecParams[1])); + + if (!msg->SetVector2D(strField, vec)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbAddInt(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + if (!msg->AddInt32OrUnsigned(strField, params[3])) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbAddFloat(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + if (!msg->AddFloatOrDouble(strField, sp_ctof(params[3]))) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbAddBool(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + bool value = (params[3] == 0 ? false : true); + if (!msg->AddBool(strField, value)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbAddString(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + char *strValue; + if ((err=pCtx->LocalToString(params[3], &strValue)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + if (!msg->AddString(strField, strValue)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbAddColor(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *clrParams; + if ((err=pCtx->LocalToPhysAddr(params[3], &clrParams)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + Color clr( + clrParams[0], + clrParams[1], + clrParams[2], + clrParams[3]); + + if (!msg->AddColor(strField, clr)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbAddAngle(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *angParams; + if ((err=pCtx->LocalToPhysAddr(params[3], &angParams)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + QAngle ang( + sp_ctof(angParams[0]), + sp_ctof(angParams[1]), + sp_ctof(angParams[2])); + + if (!msg->AddQAngle(strField, ang)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbAddVector(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *vecParams; + if ((err=pCtx->LocalToPhysAddr(params[3], &vecParams)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + Vector vec( + sp_ctof(vecParams[0]), + sp_ctof(vecParams[1]), + sp_ctof(vecParams[2])); + + if (!msg->AddVector(strField, vec)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbAddVector2D(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + cell_t *vecParams; + if ((err=pCtx->LocalToPhysAddr(params[3], &vecParams)) != SP_ERROR_NONE) + { + pCtx->ThrowNativeErrorEx(err, NULL); + return 0; + } + + Vector2D vec( + sp_ctof(vecParams[0]), + sp_ctof(vecParams[1])); + + if (!msg->AddVector2D(strField, vec)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + return 1; +} + +static cell_t smn_PbReadMessage(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + protobuf::Message *innerMsg; + if (!msg->GetMessage(strField, &innerMsg)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + Handle_t outHndl = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(innerMsg), NULL, g_pCoreIdent, NULL); + msg->AddChildHandle(outHndl); + + return outHndl; +} + +static cell_t smn_PbReadRepeatedMessage(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + const protobuf::Message *innerMsg; + if (!msg->GetRepeatedMessage(strField, params[3], &innerMsg)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\"[%d] for message \"%s\"", strField, params[3], msg->GetProtobufMessage()->GetTypeName()); + } + + Handle_t outHndl = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(const_cast(innerMsg)), NULL, g_pCoreIdent, NULL); + msg->AddChildHandle(outHndl); + + return outHndl; +} + +static cell_t smn_PbAddMessage(IPluginContext *pCtx, const cell_t *params) +{ + GET_MSG_FROM_HANDLE_OR_ERR(); + GET_FIELD_NAME_OR_ERR(); + + protobuf::Message *innerMsg; + if (!msg->AddMessage(strField, &innerMsg)) + { + return pCtx->ThrowNativeError("Invalid field \"%s\" for message \"%s\"", strField, msg->GetProtobufMessage()->GetTypeName()); + } + + Handle_t outHndl = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(innerMsg), NULL, g_pCoreIdent, NULL); + msg->AddChildHandle(outHndl); + + return outHndl; +} + +REGISTER_NATIVES(protobufnatives) +{ + {"PbReadInt", smn_PbReadInt}, + {"PbReadFloat", smn_PbReadFloat}, + {"PbReadBool", smn_PbReadBool}, + {"PbReadString", smn_PbReadString}, + {"PbReadColor", smn_PbReadColor}, + {"PbReadAngle", smn_PbReadAngle}, + {"PbReadVector", smn_PbReadVector}, + {"PbReadVector2D", smn_PbReadVector2D}, + {"PbGetRepeatedFieldCount", smn_PbGetRepeatedFieldCount}, + {"PbReadRepeatedInt", smn_PbReadRepeatedInt}, + {"PbReadRepeatedFloat", smn_PbReadRepeatedFloat}, + {"PbReadRepeatedBool", smn_PbReadRepeatedBool}, + {"PbReadRepeatedString", smn_PbReadRepeatedString}, + {"PbReadRepeatedColor", smn_PbReadRepeatedColor}, + {"PbReadRepeatedAngle", smn_PbReadRepeatedAngle}, + {"PbReadRepeatedVector", smn_PbReadRepeatedVector}, + {"PbReadRepeatedVector2D", smn_PbReadRepeatedVector2D}, + {"PbSetInt", smn_PbSetInt}, + {"PbSetFloat", smn_PbSetFloat}, + {"PbSetBool", smn_PbSetBool}, + {"PbSetString", smn_PbSetString}, + {"PbSetColor", smn_PbSetColor}, + {"PbSetAngle", smn_PbSetAngle}, + {"PbSetVector", smn_PbSetVector}, + {"PbSetVector2D", smn_PbSetVector2D}, + {"PbAddInt", smn_PbAddInt}, + {"PbAddFloat", smn_PbAddFloat}, + {"PbAddBool", smn_PbAddBool}, + {"PbAddString", smn_PbAddString}, + {"PbAddColor", smn_PbAddColor}, + {"PbAddAngle", smn_PbAddAngle}, + {"PbAddVector", smn_PbAddVector}, + {"PbAddVector2D", smn_PbAddVector2D}, + {"PbReadMessage", smn_PbReadMessage}, + {"PbReadRepeatedMessage", smn_PbReadRepeatedMessage}, + {"PbAddMessage", smn_PbAddMessage}, + {NULL, NULL} +}; + +/* + @@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@ @@@@@@@@@@@@@ + @@@@@@@@ @@@@@@@@@@@@@ + @@@@@@ @@@@@@@@@@@@@@@ + 0000 @@@@@@@@@@@@@@@@@@@@@ + 000000000 @@@@@@@@@@@@@@@@@@@ + 0000000000000000000 @@@@@@@@@@@@@@@ + 00000000000000000000 @@@@@@@@@@@@@@@ + 000000000 @@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@ @@@@ + @@@@@@@@@@@@@@@@@@@ @@@@@@@ + @@@ @@@@ @@@ @@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@ @@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@ @@@@@@@@ @@ @@@@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@@ @@ @@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@ @@ @@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@ @@@@ @@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@ @@ @@@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@ @@@@ @@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@ @@@ @@@@@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@ @@@@ @@@@@@@@@@@ + @@@@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@ @@@@@ @@@@@@ + @@@@@@@@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@ @@ @@@@@ @@@@@@@@ + @@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@ @@@@@@ @@@@ @@@@@@ + @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@ @@@@@@ @@@@@@ @@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@ @@@@@@@@ @@@@ + @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@ @ @@@@@ + @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@ @@@@@ @@@@ //// + //////////// @@@@@@@@@@@ @@@@@@ @@@@@@@@@@@@@@@@@@@@ @@ @@@@@@@@@ @@@@ //// //////////// + ///////////////// /// @@@@@ @@@@ @@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@ @@@@ ///// /////// ///////// + ///////////////////// ///// @@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@ @@@@@@@ @ @@@@ ////// /////// /////////////// + ///////////////////////// /////// @@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@ @@@@ ////// //////// //////////////////// + //////////////////////////// ////////// @@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@ @@@ ////// ////////// //////////////////////// +//////////////////// ////////// /////////// @@@@@@@@@@@@@@@@@ @@@@@@@@ @@@ @@@@@@ ////// //////////// ////////////////////////// +//////////////////// //////////// /////////// @@@@@@@@@@@@@@@@ @@@@ ///////////////////// ///////////////////////////// +///////////////////// ////////////// ////// @@@@@@@@@ /////////////////////////////////////////////////////////// + //////////////////// ///////////////////////////////////// /////////////////////////////////////////////////////////////////////// + ///////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////// +*/ +#endif // USE_PROTOBUF_USERMESSAGES diff --git a/core/smn_usermsgs.cpp b/core/smn_usermsgs.cpp index 3cf52fdc..911d1893 100644 --- a/core/smn_usermsgs.cpp +++ b/core/smn_usermsgs.cpp @@ -31,15 +31,22 @@ #include "HandleSys.h" #include "PluginSys.h" -#include "UserMessages.h" #include "PlayerManager.h" #include "smn_usermsgs.h" +#ifdef USE_PROTOBUF_USERMESSAGES +#include "UserMessagePBHelpers.h" +#endif + +HandleType_t g_ProtobufType = NO_HANDLE_TYPE; +HandleType_t g_WrBitBufType = NO_HANDLE_TYPE; +HandleType_t g_RdBitBufType = NO_HANDLE_TYPE; -HandleType_t g_WrBitBufType; -HandleType_t g_RdBitBufType; Handle_t g_CurMsgHandle; + +#ifndef USE_PROTOBUF_USERMESSAGES Handle_t g_ReadBufHandle; bf_read g_ReadBitBuf; +#endif int g_MsgPlayers[256]; bool g_IsMsgInExec = false; @@ -85,10 +92,14 @@ void UsrMessageNatives::OnSourceModAllInitialized() g_HandleSys.InitAccessDefaults(NULL, &sec); sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY; +#ifdef USE_PROTOBUF_USERMESSAGES + g_ProtobufType = g_HandleSys.CreateType("ProtobufUM", this, 0, NULL, NULL, g_pCoreIdent, NULL); +#else g_WrBitBufType = g_HandleSys.CreateType("BitBufWriter", this, 0, NULL, NULL, g_pCoreIdent, NULL); g_RdBitBufType = g_HandleSys.CreateType("BitBufReader", this, 0, NULL, &sec, g_pCoreIdent, NULL); g_ReadBufHandle = g_HandleSys.CreateHandle(g_RdBitBufType, &g_ReadBitBuf, NULL, g_pCoreIdent, NULL); +#endif g_PluginSys.AddPluginsListener(this); } @@ -98,6 +109,11 @@ void UsrMessageNatives::OnSourceModShutdown() HandleSecurity sec; sec.pIdentity = g_pCoreIdent; +#ifdef USE_PROTOBUF_USERMESSAGES + g_HandleSys.RemoveType(g_ProtobufType, g_pCoreIdent); + + g_ProtobufType = 0; +#else g_HandleSys.FreeHandle(g_ReadBufHandle, &sec); g_HandleSys.RemoveType(g_WrBitBufType, g_pCoreIdent); @@ -105,15 +121,24 @@ void UsrMessageNatives::OnSourceModShutdown() g_WrBitBufType = 0; g_RdBitBufType = 0; +#endif } void UsrMessageNatives::OnHandleDestroy(HandleType_t type, void *object) { +#ifdef USE_PROTOBUF_USERMESSAGES + delete (SMProtobufMessage *)object; +#endif } bool UsrMessageNatives::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) { +#ifdef USE_PROTOBUF_USERMESSAGES + // Different messages have different sizes, but this works as an approximate + *pSize = sizeof(protobuf::Message) + sizeof(SMProtobufMessage); +#else *pSize = sizeof(bf_read); +#endif return true; } @@ -275,37 +300,69 @@ IPluginFunction *MsgListenerWrapper::GetNotifyFunction() const return m_Notify; } +#ifdef USE_PROTOBUF_USERMESSAGES +void MsgListenerWrapper::OnUserMessage(int msg_id, protobuf::Message *msg, IRecipientFilter *pFilter) +#else void MsgListenerWrapper::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) +#endif { cell_t res; + Handle_t hndl; size_t size = _FillInPlayers(g_MsgPlayers, pFilter); +#ifdef USE_PROTOBUF_USERMESSAGES + hndl = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), NULL, g_pCoreIdent, NULL); +#else g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten()); + hndl = g_ReadBufHandle; +#endif m_Hook->PushCell(msg_id); - m_Hook->PushCell(g_ReadBufHandle); + m_Hook->PushCell(hndl); m_Hook->PushArray(g_MsgPlayers, size); m_Hook->PushCell(size); m_Hook->PushCell(pFilter->IsReliable()); m_Hook->PushCell(pFilter->IsInitMessage()); m_Hook->Execute(&res); + +#ifdef USE_PROTOBUF_USERMESSAGES + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + g_HandleSys.FreeHandle(hndl, &sec); +#endif } +#ifdef USE_PROTOBUF_USERMESSAGES +ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, protobuf::Message *msg, IRecipientFilter *pFilter) +#else ResultType MsgListenerWrapper::InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) +#endif { + Handle_t hndl; cell_t res = static_cast(Pl_Continue); size_t size = _FillInPlayers(g_MsgPlayers, pFilter); +#ifdef USE_PROTOBUF_USERMESSAGES + hndl = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), NULL, g_pCoreIdent, NULL); +#else g_ReadBitBuf.StartReading(bf->GetBasePointer(), bf->GetNumBytesWritten()); + hndl = g_ReadBufHandle; +#endif m_Intercept->PushCell(msg_id); - m_Intercept->PushCell(g_ReadBufHandle); + m_Intercept->PushCell(hndl); m_Intercept->PushArray(g_MsgPlayers, size); m_Intercept->PushCell(size); m_Intercept->PushCell(pFilter->IsReliable()); m_Intercept->PushCell(pFilter->IsInitMessage()); m_Intercept->Execute(&res); +#ifdef USE_PROTOBUF_USERMESSAGES + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + g_HandleSys.FreeHandle(hndl, &sec); +#endif + return static_cast(res); } @@ -330,6 +387,11 @@ void MsgListenerWrapper::OnPostUserMessage(int msg_id, bool sent) static UsrMessageNatives s_UsrMessageNatives; +static cell_t smn_GetUserMessageType(IPluginContext *pCtx, const cell_t *params) +{ + return g_UserMsgs.GetUserMessageType(); +} + static cell_t smn_GetUserMessageId(IPluginContext *pCtx, const cell_t *params) { char *msgname; @@ -353,7 +415,6 @@ static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params) cell_t *cl_array; unsigned int numClients; int msgid; - bf_write *pBitBuf; int client; CPlayer *pPlayer = NULL; @@ -387,13 +448,24 @@ static cell_t smn_StartMessage(IPluginContext *pCtx, const cell_t *params) } } - pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, numClients, params[4]); +#ifdef USE_PROTOBUF_USERMESSAGES + protobuf::Message *msg = g_UserMsgs.StartProtobufMessage(msgid, cl_array, numClients, params[4]); + if (!msg) + { + return pCtx->ThrowNativeError("Unable to execute a new message while in hook"); + } + + g_CurMsgHandle = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), pCtx->GetIdentity(), g_pCoreIdent, NULL); +#else + bf_write *pBitBuf = g_UserMsgs.StartBitBufMessage(msgid, cl_array, numClients, params[4]); if (!pBitBuf) { return pCtx->ThrowNativeError("Unable to execute a new message while in hook"); } g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL); +#endif + g_IsMsgInExec = true; return g_CurMsgHandle; @@ -403,7 +475,6 @@ static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params) { cell_t *cl_array; unsigned int numClients; - bf_write *pBitBuf; int client; CPlayer *pPlayer = NULL; int msgid = params[1]; @@ -436,13 +507,23 @@ static cell_t smn_StartMessageEx(IPluginContext *pCtx, const cell_t *params) } } - pBitBuf = g_UserMsgs.StartMessage(msgid, cl_array, numClients, params[4]); +#ifdef USE_PROTOBUF_USERMESSAGES + protobuf::Message *msg = g_UserMsgs.StartProtobufMessage(msgid, cl_array, numClients, params[4]); + if (!msg) + { + return pCtx->ThrowNativeError("Unable to execute a new message while in hook"); + } + + g_CurMsgHandle = g_HandleSys.CreateHandle(g_ProtobufType, new SMProtobufMessage(msg), pCtx->GetIdentity(), g_pCoreIdent, NULL); +#else + bf_write *pBitBuf = g_UserMsgs.StartBitBufMessage(msgid, cl_array, numClients, params[4]); if (!pBitBuf) { return pCtx->ThrowNativeError("Unable to execute a new message while in hook"); } g_CurMsgHandle = g_HandleSys.CreateHandle(g_WrBitBufType, pBitBuf, pCtx->GetIdentity(), g_pCoreIdent, NULL); +#endif g_IsMsgInExec = true; return g_CurMsgHandle; @@ -534,6 +615,7 @@ static cell_t smn_UnhookUserMessage(IPluginContext *pCtx, const cell_t *params) REGISTER_NATIVES(usrmsgnatives) { + {"GetUserMessageType", smn_GetUserMessageType}, {"GetUserMessageId", smn_GetUserMessageId}, {"GetUserMessageName", smn_GetUserMessageName}, {"StartMessage", smn_StartMessage}, diff --git a/core/smn_usermsgs.h b/core/smn_usermsgs.h index 0e761d9d..a96e3e0e 100644 --- a/core/smn_usermsgs.h +++ b/core/smn_usermsgs.h @@ -32,9 +32,14 @@ #ifndef _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ #define _INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ -extern int g_MsgPlayers[256]; +#include "UserMessages.h" -class MsgListenerWrapper : public IUserMessageListener +class MsgListenerWrapper +#ifdef USE_PROTOBUF_USERMESSAGES + : public IProtobufUserMessageListener +#else + : public IBitBufUserMessageListener +#endif { public: void Initialize(int msgid, IPluginFunction *hook, IPluginFunction *notify, bool intercept); @@ -43,8 +48,13 @@ public: IPluginFunction *GetHookedFunction() const; IPluginFunction *GetNotifyFunction() const; public: //IUserMessageListener +#ifdef USE_PROTOBUF_USERMESSAGES + void OnUserMessage(int msg_id, protobuf::Message *msg, IRecipientFilter *pFilter); + ResultType InterceptUserMessage(int msg_id, protobuf::Message *msg, IRecipientFilter *pFilter); +#else void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter); +#endif void OnPostUserMessage(int msg_id, bool sent); private: size_t _FillInPlayers(int *pl_array, IRecipientFilter *pFilter); @@ -56,4 +66,8 @@ private: int m_MsgId; }; +extern HandleType_t g_WrBitBufType; +extern HandleType_t g_RdBitBufType; +extern HandleType_t g_ProtobufType; + #endif //_INCLUDE_SOURCEMOD_CMSGLISTENERWRAPPER_H_ diff --git a/core/sourcemod.h b/core/sourcemod.h index 18ffa667..420ba8a6 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -152,7 +152,5 @@ private: extern bool g_Loaded; extern bool sm_show_debug_spew; extern SourceModBase g_SourceMod; -extern HandleType_t g_WrBitBufType; //:TODO: find a better place for this -extern HandleType_t g_RdBitBufType; //:TODO: find a better place for this #endif //_INCLUDE_SOURCEMOD_GLOBALHEADER_H_ diff --git a/plugins/funcommands/blind.sp b/plugins/funcommands/blind.sp index 1823e119..939a3758 100644 --- a/plugins/funcommands/blind.sp +++ b/plugins/funcommands/blind.sp @@ -38,23 +38,39 @@ PerformBlind(client, target, amount) new targets[2]; targets[0] = target; - new Handle:message = StartMessageEx(g_FadeUserMsgId, targets, 1); - BfWriteShort(message, 1536); - BfWriteShort(message, 1536); - + new duration = 1536; + new holdtime = 1536; + new flags; if (amount == 0) { - BfWriteShort(message, (0x0001 | 0x0010)); + flags = (0x0001 | 0x0010); } else { - BfWriteShort(message, (0x0002 | 0x0008)); + flags = (0x0002 | 0x0008); } - BfWriteByte(message, 0); - BfWriteByte(message, 0); - BfWriteByte(message, 0); - BfWriteByte(message, amount); + new color[4] = { 0, 0, 0, 0 }; + color[3] = amount; + + new Handle:message = StartMessageEx(g_FadeUserMsgId, targets, 1); + if (GetUserMessageType() == UM_Protobuf) + { + PbSetInt(message, "duration", duration); + PbSetInt(message, "hold_time", holdtime); + PbSetInt(message, "flags", flags); + PbSetColor(message, "clr", color); + } + else + { + BfWriteShort(message, duration); + BfWriteShort(message, holdtime); + BfWriteShort(message, flags); + BfWriteByte(message, color[0]); + BfWriteByte(message, color[1]); + BfWriteByte(message, color[2]); + BfWriteByte(message, color[3]); + } EndMessage(); diff --git a/plugins/funcommands/drug.sp b/plugins/funcommands/drug.sp index 3b223a86..2e665b6f 100644 --- a/plugins/funcommands/drug.sp +++ b/plugins/funcommands/drug.sp @@ -51,17 +51,34 @@ KillDrug(client) TeleportEntity(client, NULL_VECTOR, angs, NULL_VECTOR); new clients[2]; - clients[0] = client; - + clients[0] = client; + + new duration = 1536; + new holdtime = 1536; + new flags = (0x0001 | 0x0010); + new color[4] = { 0, 0, 0, 0 }; + new Handle:message = StartMessageEx(g_FadeUserMsgId, clients, 1); - BfWriteShort(message, 1536); - BfWriteShort(message, 1536); - BfWriteShort(message, (0x0001 | 0x0010)); - BfWriteByte(message, 0); - BfWriteByte(message, 0); - BfWriteByte(message, 0); - BfWriteByte(message, 0); - EndMessage(); + + if (GetUserMessageType() == UM_Protobuf) + { + PbSetInt(message, "duration", duration); + PbSetInt(message, "hold_time", holdtime); + PbSetInt(message, "flags", flags); + PbSetColor(message, "clr", color); + } + else + { + BfWriteShort(message, duration); + BfWriteShort(message, holdtime); + BfWriteShort(message, flags); + BfWriteByte(message, color[0]); + BfWriteByte(message, color[1]); + BfWriteByte(message, color[2]); + BfWriteByte(message, color[3]); + } + + EndMessage(); } KillDrugTimer(client) @@ -152,16 +169,35 @@ public Action:Timer_Drug(Handle:timer, any:client) new clients[2]; clients[0] = client; + new duration = 255; + new holdtime = 255; + new flags = 0x0002; + new color[4] = { 0, 0, 0, 128 }; + color[0] = GetRandomInt(0,255); + color[1] = GetRandomInt(0,255); + color[2] = GetRandomInt(0,255); + new Handle:message = StartMessageEx(g_FadeUserMsgId, clients, 1); - BfWriteShort(message, 255); - BfWriteShort(message, 255); - BfWriteShort(message, (0x0002)); - BfWriteByte(message, GetRandomInt(0,255)); - BfWriteByte(message, GetRandomInt(0,255)); - BfWriteByte(message, GetRandomInt(0,255)); - BfWriteByte(message, 128); - EndMessage(); + if (GetUserMessageType() == UM_Protobuf) + { + PbSetInt(message, "duration", duration); + PbSetInt(message, "hold_time", holdtime); + PbSetInt(message, "flags", flags); + PbSetColor(message, "clr", color); + } + else + { + BfWriteShort(message, duration); + BfWriteShort(message, holdtime); + BfWriteShort(message, flags); + BfWriteByte(message, color[0]); + BfWriteByte(message, color[1]); + BfWriteByte(message, color[2]); + BfWriteByte(message, color[3]); + } + + EndMessage(); return Plugin_Handled; } diff --git a/plugins/include/core.inc b/plugins/include/core.inc index 708702f3..6a061c66 100644 --- a/plugins/include/core.inc +++ b/plugins/include/core.inc @@ -167,6 +167,67 @@ public __ext_core_SetNTVOptional() MarkNativeAsOptional("RequireFeature"); MarkNativeAsOptional("AddCommandListener"); MarkNativeAsOptional("RemoveCommandListener"); + + MarkNativeAsOptional("BfWriteBool"); + MarkNativeAsOptional("BfWriteByte"); + MarkNativeAsOptional("BfWriteChar"); + MarkNativeAsOptional("BfWriteShort"); + MarkNativeAsOptional("BfWriteWord"); + MarkNativeAsOptional("BfWriteNum"); + MarkNativeAsOptional("BfWriteFloat"); + MarkNativeAsOptional("BfWriteString"); + MarkNativeAsOptional("BfWriteEntity"); + MarkNativeAsOptional("BfWriteAngle"); + MarkNativeAsOptional("BfWriteCoord"); + MarkNativeAsOptional("BfWriteVecCoord"); + MarkNativeAsOptional("BfWriteVecNormal"); + MarkNativeAsOptional("BfWriteAngles"); + MarkNativeAsOptional("BfReadBool"); + MarkNativeAsOptional("BfReadByte"); + MarkNativeAsOptional("BfReadChar"); + MarkNativeAsOptional("BfReadShort"); + MarkNativeAsOptional("BfReadWord"); + MarkNativeAsOptional("BfReadNum"); + MarkNativeAsOptional("BfReadFloat"); + MarkNativeAsOptional("BfReadString"); + MarkNativeAsOptional("BfReadEntity"); + MarkNativeAsOptional("BfReadAngle"); + MarkNativeAsOptional("BfReadCoord"); + MarkNativeAsOptional("BfReadVecCoord"); + MarkNativeAsOptional("BfReadVecNormal"); + MarkNativeAsOptional("BfReadAngles"); + MarkNativeAsOptional("BfGetNumBytesLeft"); + + MarkNativeAsOptional("PbReadInt"); + MarkNativeAsOptional("PbReadFloat"); + MarkNativeAsOptional("PbReadString"); + MarkNativeAsOptional("PbReadColor"); + MarkNativeAsOptional("PbReadAngle"); + MarkNativeAsOptional("PbReadVector"); + MarkNativeAsOptional("PbReadVector2D"); + MarkNativeAsOptional("PbGetRepeatedFieldCount"); + MarkNativeAsOptional("PbReadRepeatedInt"); + MarkNativeAsOptional("PbReadRepeatedFloat"); + MarkNativeAsOptional("PbReadRepeatedString"); + MarkNativeAsOptional("PbReadRepeatedColor"); + MarkNativeAsOptional("PbReadRepeatedAngle"); + MarkNativeAsOptional("PbReadRepeatedVector"); + MarkNativeAsOptional("PbReadRepeatedVector2D"); + MarkNativeAsOptional("PbSetInt"); + MarkNativeAsOptional("PbSetFloat"); + MarkNativeAsOptional("PbSetString"); + MarkNativeAsOptional("PbSetColor"); + MarkNativeAsOptional("PbSetAngle"); + MarkNativeAsOptional("PbSetVector"); + MarkNativeAsOptional("PbSetVector2D"); + MarkNativeAsOptional("PbAddInt"); + MarkNativeAsOptional("PbAddFloat"); + MarkNativeAsOptional("PbAddString"); + MarkNativeAsOptional("PbAddColor"); + MarkNativeAsOptional("PbAddAngle"); + MarkNativeAsOptional("PbAddVector"); + MarkNativeAsOptional("PbAddVector2D"); + VerifyCoreVersion(); } diff --git a/plugins/include/protobuf.inc b/plugins/include/protobuf.inc new file mode 100644 index 00000000..db982f9d --- /dev/null +++ b/plugins/include/protobuf.inc @@ -0,0 +1,433 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod (C)2013 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This file is part of the SourceMod/SourcePawn SDK. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#if defined _protobuf_included +#endinput +#endif +#define _protobuf_included + +/** + * Reads an int32, uint32, sint32, fixed32, or sfixed32 from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @return Integer value read. + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadInt(Handle:pb, const String:field[]); + +/** + * Reads a float or downcasted double from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @return Float value read. + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native Float:PbReadFloat(Handle:pb, const String:field[]); + +/** + * Reads a bool from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @return Boolean value read. + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native bool:PbReadBool(Handle:pb, const String:field[]); + +/** + * Reads a string from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadString(Handle:pb, const String:field[], String:buffer[], maxlength); + +/** + * Reads an RGBA color value from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param buffer Destination color buffer. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadColor(Handle:pb, const String:field[], buffer[4]); + +/** + * Reads an XYZ angle value from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param buffer Destination angle buffer. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadAngle(Handle:pb, const String:field[], Float:buffer[3]); + +/** + * Reads an XYZ vector value from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param buffer Destination vector buffer. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadVector(Handle:pb, const String:field[], Float:buffer[3]); + +/** + * Reads an XY vector value from a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param buffer Destination vector buffer. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadVector2D(Handle:pb, const String:field[], Float:buffer[2]); + +/** + * Gets the number of elements in a repeated field of a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @return Number of elements in the field. + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbGetRepeatedFieldCount(Handle:pb, const String:field[]); + +/** + * Reads an int32, uint32, sint32, fixed32, or sfixed32 from a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index in the repeated field. + * @return Integer value read. + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadRepeatedInt(Handle:pb, const String:field[], index); + +/** + * Reads a float or downcasted double from a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index in the repeated field. + * @return Float value read. + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native Float:PbReadRepeatedFloat(Handle:pb, const String:field[], index); + +/** + * Reads a bool from a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index in the repeated field. + * @return Boolean value read. + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native bool:PbReadRepeatedBool(Handle:pb, const String:field[], index); + +/** + * Reads a string from a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index in the repeated field. + * @param buffer Destination string buffer. + * @param maxlength Maximum length of output string buffer. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadRepeatedString(Handle:pb, const String:field[], index, String:buffer[], size); + +/** + * Reads an RGBA color value from a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index in the repeated field. + * @param buffer Destination color buffer. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadRepeatedColor(Handle:pb, const String:field[], index, buffer[4]); + +/** + * Reads an XYZ angle value from a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index in the repeated field. + * @param buffer Destination angle buffer. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadRepeatedAngle(Handle:pb, const String:field[], index, Float:buffer[3]); + +/** + * Reads an XYZ vector value from a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index in the repeated field. + * @param buffer Destination vector buffer. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadRepeatedVector(Handle:pb, const String:field[], index, Float:buffer[3]); + +/** + * Reads an XY vector value from a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index in the repeated field. + * @param buffer Destination vector buffer. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbReadRepeatedVector2D(Handle:pb, const String:field[], index, Float:buffer[2]); + +/** + * Sets an int32, uint32, sint32, fixed32, or sfixed32 on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Integer value to set. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbSetInt(Handle:pb, const String:field[], value); + +/** + * Sets a float or double on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Float value to set. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbSetFloat(Handle:pb, const String:field[], Float:value); + +/** + * Sets a bool on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Boolean value to set. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbSetBool(Handle:pb, const String:field[], bool:value); + +/** + * Sets a string on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value String value to set. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbSetString(Handle:pb, const String:field[], const String:value[]); + +/** + * Sets an RGBA color on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Color value to set. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbSetColor(Handle:pb, const String:field[], const color[4]); + +/** + * Sets an XYZ angle on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Angle value to set. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbSetAngle(Handle:pb, const String:field[], const Float:angle[3]); + +/** + * Sets an XYZ vector on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Vector value to set. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbSetVector(Handle:pb, const String:field[], const Float:vec[3]); + +/** + * Sets an XY vector on a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Vector value to set. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbSetVector2D(Handle:pb, const String:field[], const Float:vec[2]); + +/** + * Add an int32, uint32, sint32, fixed32, or sfixed32 to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Integer value to add. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbAddInt(Handle:pb, const String:field[], value); + +/** + * Add a float or double to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Float value to add. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbAddFloat(Handle:pb, const String:field[], Float:value); + +/** + * Add a bool to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Boolean value to add. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbAddBool(Handle:pb, const String:field[], bool:value); + +/** + * Add a string to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value String value to add. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbAddString(Handle:pb, const String:field[], const String:value[]); + +/** + * Add an RGBA color to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Color value to add. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbAddColor(Handle:pb, const String:field[], const color[4]); + +/** + * Add an XYZ angle to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Angle value to add. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbAddAngle(Handle:pb, const String:field[], const Float:angle[3]); + +/** + * Add an XYZ vector to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Vector value to add. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbAddVector(Handle:pb, const String:field[], const Float:vec[3]); + +/** + * Add an XY vector to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param value Vector value to add. + * @noreturn + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native PbAddVector2D(Handle:pb, const String:field[], const Float:vec[2]); + +/** + * Retrieve a handle to an embedded protobuf message in a protobuf message. + * + * @param pb protobuf handle. + * @param field Field name. + * @return protobuf handle to embedded message. + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native Handle:PbReadMessage(Handle:pb, const String:field[]); + +/** + * Retrieve a handle to an embedded protobuf message in a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @param index Index in the repeated field. + * @return protobuf handle to embedded message. + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native Handle:PbReadRepeatedMessage(Handle:pb, const String:field[], index); + +/** + * Adds an embedded protobuf message to a protobuf message repeated field. + * + * @param pb protobuf handle. + * @param field Field name. + * @return protobuf handle to added, embedded message. + * @error Invalid or incorrect Handle, non-existant field, or incorrect field type. + */ +native Handle:PbAddMessage(Handle:pb, const String:field[]); diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 7b146083..5eeac133 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -66,6 +66,7 @@ struct Plugin #include #include #include +#include #include #include #include diff --git a/plugins/include/usermessages.inc b/plugins/include/usermessages.inc index aa58297b..2f2a6c97 100644 --- a/plugins/include/usermessages.inc +++ b/plugins/include/usermessages.inc @@ -43,6 +43,15 @@ enum UserMsg INVALID_MESSAGE_ID = -1, }; +/** + * UserMsg message serialization formats + */ +enum UserMessageType +{ + UM_BitBuf = 0, + UM_Protobuf, +}; + /** * @section Message Flags. */ @@ -54,6 +63,13 @@ enum UserMsg * @endsection */ +/** + * Returns usermessage serialization type used for the current engine + * + * @return The supported usermessage type. + */ +native UserMessageType:GetUserMessageType(); + /** * Returns the ID of a given message, or -1 on failure. * @@ -115,7 +131,7 @@ native EndMessage(); * Called when a message is hooked * * @param msg_id Message index. - * @param bf Handle to the input bit buffer of the message. + * @param msg Handle to the input bit buffer or protobuf. * @param players Array containing player indexes. * @param playersNum Number of players in the array. * @param reliable True if message is reliable, false otherwise. @@ -124,7 +140,7 @@ native EndMessage(); * blocks the message from being sent, and Plugin_Continue * resumes normal functionality. */ -functag public Action:MsgHook(UserMsg:msg_id, Handle:bf, const players[], playersNum, bool:reliable, bool:init); +functag public Action:MsgHook(UserMsg:msg_id, Handle:msg, const players[], playersNum, bool:reliable, bool:init); /** * Called when a message hook has completed. diff --git a/public/IUserMessages.h b/public/IUserMessages.h index 014a9af2..3d56b5a5 100644 --- a/public/IUserMessages.h +++ b/public/IUserMessages.h @@ -35,50 +35,36 @@ #include #include #include -#include #include +namespace google { namespace protobuf { + class Message; +} }; + +class bf_write; + /** * @file IUserMessages.h * @brief Contains functions for advanced usermessage hooking. */ #define SMINTERFACE_USERMSGS_NAME "IUserMessages" -#define SMINTERFACE_USERMSGS_VERSION 3 +#define SMINTERFACE_USERMSGS_VERSION 4 namespace SourceMod { + enum UserMessageType + { + UM_BitBuf, + UM_Protobuf, + }; + /** * @brief Listens to user messages sent from the server. */ class IUserMessageListener { public: - /** - * @brief Called when a hooked user message is being sent - * and all interceptions have finished. - * - * @param msg_id Message Id. - * @param bf bf_write structure containing written bytes. - * @param pFilter Recipient filter. - */ - virtual void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) - { - } - - /** - * @brief Called when a hooked user message is intercepted. - * - * @param msg_id Message Id. - * @param bf bf_write structure containing written bytes. - * @param pFilter Recipient filter. - * @return Pl_Continue to allow message, Pl_Stop or Pl_Handled to scrap it. - */ - virtual ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) - { - return Pl_Continue; - } - /** * @brief Called when a hooked user message is sent, regardless of the hook type. * @@ -110,6 +96,76 @@ namespace SourceMod virtual void OnPostUserMessage(int msg_id, bool sent) { } + + virtual UserMessageType GetUserMessageType() const =0; + }; + + class IBitBufUserMessageListener : public IUserMessageListener + { + public: + /** + * @brief Called when a hooked user message is being sent + * and all interceptions have finished. + * + * @param msg_id Message Id. + * @param bf bf_write structure containing written bytes. + * @param pFilter Recipient filter. + */ + virtual void OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) + { + } + + /** + * @brief Called when a hooked user message is intercepted. + * + * @param msg_id Message Id. + * @param bf bf_write structure containing written bytes. + * @param pFilter Recipient filter. + * @return Pl_Continue to allow message, Pl_Stop or Pl_Handled to scrap it. + */ + virtual ResultType InterceptUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) + { + return Pl_Continue; + } + + virtual UserMessageType GetUserMessageType() const + { + return UM_BitBuf; + } + }; + + class IProtobufUserMessageListener : public IUserMessageListener + { + public: + /** + * @brief Called when a hooked user message is being sent + * and all interceptions have finished. + * + * @param msg_id Message Id. + * @param msg Protobuf Message structure containing message data. + * @param pFilter Recipient filter. + */ + virtual void OnUserMessage(int msg_id, google::protobuf::Message *msg, IRecipientFilter *pFilter) + { + } + + /** + * @brief Called when a hooked user message is intercepted. + * + * @param msg_id Message Id. + * @param msg Protobuf Message structure containing message data. + * @param pFilter Recipient filter. + * @return Pl_Continue to allow message, Pl_Stop or Pl_Handled to scrap it. + */ + virtual ResultType InterceptUserMessage(int msg_id, google::protobuf::Message *msg, IRecipientFilter *pFilter) + { + return Pl_Continue; + } + + virtual UserMessageType GetUserMessageType() const + { + return UM_Protobuf; + } }; #define USERMSG_RELIABLE (1<<2) /**< Message will be set to reliable */ @@ -173,7 +229,12 @@ namespace SourceMod * @param flags Flags to use for sending the message. * @return bf_write structure to write message with, or NULL on failure. */ - virtual bf_write *StartMessage(int msg_id, + virtual bf_write *StartBitBufMessage(int msg_id, + const cell_t players[], + unsigned int playersNum, + int flags) =0; + + virtual google::protobuf::Message *StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags) =0; @@ -218,6 +279,13 @@ namespace SourceMod * @return A message index, or -1 on failure. */ virtual bool GetMessageName(int msgid, char *buffer, size_t maxlength) const =0; + + /** + * @brief Returns usermessage serialization type used for the current engine. + * + * @return The supported usermessage type. + */ + virtual UserMessageType GetUserMessageType() const =0; }; }