Updated protobuf and usermessage support for Dota 2 (bug 5656, r=asherkin).

This commit is contained in:
Nicholas Hastings 2013-03-19 11:19:38 -04:00
parent 877ef76540
commit e364937353
7 changed files with 174 additions and 37 deletions

View File

@ -42,7 +42,9 @@
#include "logic_bridge.h"
#include <tier0/mem.h>
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_DOTA
#include <game/shared/protobuf/usermessages.pb.h>
#elif SOURCE_ENGINE == SE_CSGO
#include <cstrike15_usermessages.pb.h>
#endif
@ -512,7 +514,7 @@ void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
{
#if SOURCE_ENGINE != SE_CSGO
#ifndef USE_PROTOBUF_USERMESSAGES
bf_write *pBitBuf = NULL;
#endif
cell_t players[] = {client};
@ -527,7 +529,17 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
char buffer[192];
UTIL_Format(buffer, sizeof(buffer), "%s\1\n", msg);
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_SayText *pMsg;
if ((pMsg = (CUserMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_client(0);
pMsg->set_text(buffer);
pMsg->set_chat(false);
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_SayText *pMsg;
if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
@ -554,7 +566,20 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
}
}
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_TextMsg *pMsg;
if ((pMsg = (CUserMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_dest(dest);
pMsg->add_param(msg);
pMsg->add_param("");
pMsg->add_param("");
pMsg->add_param("");
pMsg->add_param("");
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_TextMsg *pMsg;
if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
@ -587,7 +612,15 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
{
cell_t players[] = {client};
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_HintText *pMsg;
if ((pMsg = (CUserMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_message(msg);
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_HintText *pMsg;
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
@ -617,7 +650,15 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
{
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_HintText *pMsg;
if ((pMsg = (CUserMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
{
return false;
}
pMsg->set_message(msg);
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_HintText *pMsg;
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
{
@ -652,7 +693,13 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
int count = 0;
cell_t players[] = {client};
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_VGUIMenu *pMsg;
if ((pMsg = (CUserMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
{
return false;
}
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_VGUIMenu *pMsg;
if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
{
@ -677,7 +724,18 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
SubKey = data->GetFirstSubKey();
}
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_DOTA
pMsg->set_name(name);
pMsg->set_show(show);
while (SubKey)
{
CUserMsg_VGUIMenu_Keys *key = pMsg->add_keys();
key->set_name(SubKey->GetName());
key->set_value(SubKey->GetString());
SubKey = SubKey->GetNextKey();
}
#elif SOURCE_ENGINE == SE_CSGO
pMsg->set_name(name);
pMsg->set_show(show);

View File

@ -138,7 +138,11 @@ void CRadioStyle::OnSourceModShutdown()
bool CRadioStyle::IsSupported()
{
#if SOURCE_ENGINE == SE_DOTA
return false;
#else
return (g_ShowMenuId != -1);
#endif
}
bool CRadioStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd)
@ -169,6 +173,7 @@ void CRadioStyle::OnUserMessage(int msg_id, protobuf::Message &msg, IRecipientFi
void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
#endif
{
#if SOURCE_ENGINE != SE_DOTA
int count = pFilter->GetRecipientCount();
#ifdef USE_PROTOBUF_USERMESSAGES
@ -186,6 +191,7 @@ void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFil
{
g_last_clients[g_last_client_count++] = pFilter->GetRecipientIndex(i);
}
#endif
}
void CRadioStyle::OnUserMessageSent(int msg_id)
@ -473,6 +479,7 @@ void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
void CRadioMenuPlayer::Radio_Refresh()
{
#if SOURCE_ENGINE != SE_DOTA
cell_t players[1] = {m_index};
char *ptr = display_pkt;
char save = 0;
@ -526,6 +533,7 @@ void CRadioMenuPlayer::Radio_Refresh()
#endif
display_last_refresh = gpGlobals->curtime;
#endif // !DOTA
}
int CRadioDisplay::GetAmountRemaining()

View File

@ -675,6 +675,9 @@ public:
inline bool GetColor(const char *pszFieldName, Color *out)
{
#if SOURCE_ENGINE != SE_CSGO
return false;
#else
GETCHECK_FIELD();
CHECK_FIELD_TYPE(MESSAGE);
CHECK_FIELD_NOT_REPEATED();
@ -688,10 +691,14 @@ public:
);
return true;
#endif
}
inline bool SetColor(const char *pszFieldName, const Color &value)
{
#if SOURCE_ENGINE != SE_CSGO
return false;
#else
GETCHECK_FIELD();
CHECK_FIELD_TYPE(MESSAGE);
CHECK_FIELD_NOT_REPEATED();
@ -703,10 +710,14 @@ public:
msgRGBA->set_a(value.a());
return true;
#endif
}
inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out)
{
#if SOURCE_ENGINE != SE_CSGO
return false;
#else
GETCHECK_FIELD();
CHECK_FIELD_TYPE(MESSAGE);
CHECK_FIELD_REPEATED();
@ -721,10 +732,14 @@ public:
);
return true;
#endif
}
inline bool SetRepeatedColor(const char *pszFieldName, int index, const Color &value)
{
#if SOURCE_ENGINE != SE_CSGO
return false;
#else
GETCHECK_FIELD();
CHECK_FIELD_TYPE(MESSAGE);
CHECK_FIELD_REPEATED();
@ -737,10 +752,14 @@ public:
msgRGBA->set_a(value.a());
return true;
#endif
}
inline bool AddColor(const char *pszFieldName, const Color &value)
{
#if SOURCE_ENGINE != SE_CSGO
return false;
#else
GETCHECK_FIELD();
CHECK_FIELD_TYPE(MESSAGE);
CHECK_FIELD_REPEATED();
@ -752,6 +771,7 @@ public:
msgRGBA->set_a(value.a());
return true;
#endif
}
inline bool GetVector2D(const char *pszFieldName, Vector2D *out)

View File

@ -32,13 +32,15 @@
#include "UserMessages.h"
#include "sm_stringutil.h"
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_DOTA
#include <dota_usermessage_helpers.h>
#elif SOURCE_ENGINE == SE_CSGO
#include <cstrike15_usermessage_helpers.h>
#endif
UserMessages g_UserMsgs;
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
#else
#if SOURCE_ENGINE >= SE_LEFT4DEAD
@ -96,7 +98,7 @@ void UserMessages::OnSourceModAllShutdown()
{
if (m_HookCount)
{
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
@ -111,7 +113,10 @@ void UserMessages::OnSourceModAllShutdown()
int UserMessages::GetMessageIndex(const char *msg)
{
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_DOTA
// Can split this per engine and/or game later
return g_DotaUsermessageHelpers.GetIndex(msg);
#elif SOURCE_ENGINE == SE_CSGO
// Can split this per engine and/or game later
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
#else
@ -150,8 +155,12 @@ int UserMessages::GetMessageIndex(const char *msg)
bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
{
#if SOURCE_ENGINE == SE_CSGO
#ifdef USE_PROTOBUF_USERMESSAGES
#if SOURCE_ENGINE == SE_DOTA
const char *pszName = g_DotaUsermessageHelpers.GetName(msgid);
#elif SOURCE_ENGINE == SE_CSGO
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
#endif
if (!pszName)
return false;
@ -259,7 +268,7 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
if (m_CurFlags & USERMSG_BLOCKHOOKS)
{
// direct message creation, return buffer "from engine". keep track
m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
buffer = m_FakeEngineBuffer;
} else {
char messageName[32];
@ -274,12 +283,12 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
{
case MRES_IGNORED:
case MRES_HANDLED:
m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
buffer = m_FakeEngineBuffer;
break;
case MRES_OVERRIDE:
m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
// fallthrough
case MRES_SUPERCEDE:
buffer = msg;
@ -300,7 +309,7 @@ bool UserMessages::EndMessage()
return false;
}
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
if (m_CurFlags & USERMSG_BLOCKHOOKS)
{
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
@ -330,7 +339,7 @@ bool UserMessages::EndMessage()
} else {
engine->MessageEnd();
}
#endif // SE_CSGO
#endif // SE_CSGO || SE_DOTA
m_InExec = false;
m_CurFlags = 0;
@ -415,7 +424,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
if (!m_HookCount++)
{
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
@ -436,6 +445,17 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
return true;
}
#ifdef USE_PROTOBUF_USERMESSAGES
const protobuf::Message *GetMessagePrototype(int msg_type)
{
#if SOURCE_ENGINE == SE_DOTA
return g_DotaUsermessageHelpers.GetPrototype(msg_type);
#elif SOURCE_ENGINE == SE_CSGO
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
#endif
}
#endif
#ifdef USE_PROTOBUF_USERMESSAGES
bool UserMessages::InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
#else
@ -481,7 +501,7 @@ void UserMessages::_DecRefCounter()
{
if (--m_HookCount == 0)
{
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
@ -493,10 +513,14 @@ void UserMessages::_DecRefCounter()
}
}
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
{
#if SOURCE_ENGINE == SE_DOTA
OnStartMessage_Pre(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
#elif SOURCE_ENGINE == SE_CSGO
OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
#endif
if (m_FakeMetaRes == MRES_SUPERCEDE)
{
int size = msg.ByteSize();
@ -509,7 +533,11 @@ void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type,
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
}
#if SOURCE_ENGINE == SE_DOTA
OnStartMessage_Post(&filter, msg_type, g_DotaUsermessageHelpers.GetName(msg_type));
#elif SOURCE_ENGINE == SE_CSGO
OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
#endif
OnMessageEnd_Pre();
if (m_FakeMetaRes == MRES_SUPERCEDE)
@ -541,7 +569,7 @@ void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type
RETURN_META(res)
#endif
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
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)
@ -569,7 +597,8 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
#ifdef USE_PROTOBUF_USERMESSAGES
if (m_InterceptBuffer)
delete m_InterceptBuffer;
m_InterceptBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
m_InterceptBuffer = GetMessagePrototype(msg_type)->New();
UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
#else
m_InterceptBuffer.Reset();
@ -580,7 +609,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
}
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
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)
@ -745,7 +774,7 @@ void UserMessages::OnMessageEnd_Pre()
if (!handled && intercepted)
{
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
#else
bf_write *engine_bfw;
@ -757,15 +786,16 @@ 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
#endif // SE_CSGO || SE_DOTA
}
{
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
int size = m_OrigBuffer->ByteSize();
uint8 *data = (uint8 *)stackalloc(size);
m_OrigBuffer->SerializePartialToArray(data, size);
protobuf::Message *pTempMsg = g_Cstrike15UsermessageHelpers.GetPrototype(m_CurId)->New();
protobuf::Message *pTempMsg = GetMessagePrototype(m_CurId)->New();
pTempMsg->ParsePartialFromArray(data, size);
#else
bf_write *pTempMsg = m_OrigBuffer;
@ -790,7 +820,7 @@ void UserMessages::OnMessageEnd_Pre()
iter++;
}
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
delete pTempMsg;
#endif
}

View File

@ -42,7 +42,7 @@
using namespace SourceHook;
using namespace SourceMod;
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#define USE_PROTOBUF_USERMESSAGES
#endif
@ -100,12 +100,12 @@ public: //IUserMessages
bool intercept=false);
UserMessageType GetUserMessageType() const;
public:
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
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
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
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
@ -119,6 +119,7 @@ public:
void OnMessageEnd_Post();
private:
#ifdef USE_PROTOBUF_USERMESSAGES
const protobuf::Message *GetMessagePrototype(int msg_type);
bool InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
bool InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
#else

View File

@ -48,7 +48,7 @@
#include "ConsoleDetours.h"
#include "ConCommandBaseIterator.h"
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
#include <netmessages.pb.h>
#endif
@ -1435,7 +1435,7 @@ static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
char data[256];
bf_write buffer(data, sizeof(data));
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
CNETMsg_SetConVar msg;
CMsg_CVars_CVar *cvar = msg.mutable_convars()->add_cvars();

View File

@ -37,7 +37,9 @@
#include "HandleSys.h"
#include "logic_bridge.h"
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_DOTA
#include <game/shared/protobuf/usermessages.pb.h>
#elif SOURCE_ENGINE == SE_CSGO
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
#endif
@ -316,8 +318,26 @@ void UTIL_SendHudText(int client, const hud_text_parms &textparms, const char *p
players[0] = client;
#if SOURCE_ENGINE == SE_CSGO
// If or when we need to support multiple games per engine with this, we can switch to reflection
#if SOURCE_ENGINE == SE_DOTA
CUserMsg_HudMsg *msg = (CUserMsg_HudMsg *)g_UserMsgs.StartProtobufMessage(g_HudMsgNum, players, 1, 0);
msg->set_channel(textparms.channel & 0xFF);
msg->set_x(textparms.x);
msg->set_y(textparms.y);
Color c1(textparms.r1, textparms.g1, textparms.b1, textparms.a1);
msg->set_color1(c1.GetRawColor());
Color c2(textparms.r2, textparms.g2, textparms.b2, textparms.a2);
msg->set_color2(c2.GetRawColor());
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_message(pMessage);
#elif SOURCE_ENGINE == SE_CSGO
CCSUsrMsg_HudMsg *msg = (CCSUsrMsg_HudMsg *)g_UserMsgs.StartProtobufMessage(g_HudMsgNum, players, 1, 0);
msg->set_channel(textparms.channel & 0xFF);