Added initial support for protobuf usermessages on CS:GO (bug 5579, r=asherkin).

This commit is contained in:
Nicholas Hastings 2013-01-22 21:43:12 -05:00
parent f757d5f09b
commit 312e26a5cf
22 changed files with 3106 additions and 110 deletions

View File

@ -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')

View File

@ -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()

View File

@ -42,6 +42,10 @@
#include "logic_bridge.h"
#include <tier0/mem.h>
#if SOURCE_ENGINE == SE_CSGO
#include <cstrike15_usermessages.pb.h>
#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;

View File

@ -39,6 +39,14 @@
#endif
#include "logic_bridge.h"
#ifdef USE_PROTOBUF_USERMESSAGES
#include <google/protobuf/descriptor.h>
#endif
#if SOURCE_ENGINE == SE_CSGO
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
#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;
}

View File

@ -37,7 +37,7 @@
#include "MenuStyle_Base.h"
#include "sourcemm_api.h"
#include <IPlayerHelpers.h>
#include <IUserMessages.h>
#include "UserMessages.h"
#include "sm_fastlink.h"
#include <sh_stack.h>
#include <compat_wrappers.h>
@ -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();

853
core/UserMessagePBHelpers.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_SMPBMESSAGE_H_
#define _INCLUDE_SOURCEMOD_SMPBMESSAGE_H_
#include <sh_list.h>
#include <google/protobuf/descriptor.h>
#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<Handle_t> 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_

View File

@ -32,18 +32,32 @@
#include "UserMessages.h"
#include "sm_stringutil.h"
#if SOURCE_ENGINE == SE_CSGO
#include <cstrike15_usermessage_helpers.h>
#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<ListenerInfo *>::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<void **>(&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<IRecipientFilter *>(&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<IRecipientFilter *>(&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<IRecipientFilter &>(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<IRecipientFilter &>(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<IRecipientFilter &>(*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);
}

View File

@ -36,16 +36,35 @@
#include <IUserMessages.h>
#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 <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
#include <netmessages.pb.h>
using namespace google;
#else
#include <bitbuf.h>
#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<ListenerInfo *> m_msgHooks[255];
@ -98,15 +132,26 @@ private:
CStack<ListenerInfo *> 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;

View File

@ -29,11 +29,16 @@
* Version: $Id$
*/
#include "UserMessages.h"
#ifndef USE_PROTOBUF_USERMESSAGES
#include "sourcemod.h"
#include "HandleSys.h"
#include <bitbuf.h>
#include <vector.h>
#include <HalfLife2.h>
#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

View File

@ -48,6 +48,10 @@
#include "ConsoleDetours.h"
#include "ConCommandBaseIterator.h"
#if SOURCE_ENGINE == SE_CSGO
#include <netmessages.pb.h>
#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]);

View File

@ -37,6 +37,10 @@
#include "HandleSys.h"
#include "logic_bridge.h"
#if SOURCE_ENGINE == SE_CSGO
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
#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();
}

823
core/smn_protobuf.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* 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<Handle_t>(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<protobuf::Message *>(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

View File

@ -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<cell_t>(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<ResultType>(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},

View File

@ -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_

View File

@ -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_

View File

@ -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();

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* 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[]);

View File

@ -66,6 +66,7 @@ struct Plugin
#include <console>
#include <events>
#include <bitbuffer>
#include <protobuf>
#include <usermessages>
#include <menus>
#include <halflife>

View File

@ -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.

View File

@ -35,50 +35,36 @@
#include <IShareSys.h>
#include <sp_vm_api.h>
#include <IForwardSys.h>
#include <bitbuf.h>
#include <irecipientfilter.h>
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;
};
}