core/UserMessages.cpp
changeset 3743 a98686a77974
parent 3733 a4a0d91d4951
child 3757 aa69f3b742c7
     1.1 --- a/core/UserMessages.cpp	Mon Jan 07 09:09:14 2013 -0500
     1.2 +++ b/core/UserMessages.cpp	Tue Jan 22 21:43:12 2013 -0500
     1.3 @@ -32,18 +32,32 @@
     1.4  #include "UserMessages.h"
     1.5  #include "sm_stringutil.h"
     1.6  
     1.7 +#if SOURCE_ENGINE == SE_CSGO
     1.8 +#include <cstrike15_usermessage_helpers.h>
     1.9 +#endif
    1.10 +
    1.11  UserMessages g_UserMsgs;
    1.12  
    1.13 +#if SOURCE_ENGINE == SE_CSGO
    1.14 +SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
    1.15 +#else
    1.16  #if SOURCE_ENGINE >= SE_LEFT4DEAD
    1.17  SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int, const char *);
    1.18  #else
    1.19  SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
    1.20  #endif
    1.21  SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
    1.22 +#endif // ==SE_CSGO
    1.23  
    1.24 -UserMessages::UserMessages() : m_InterceptBuffer(m_pBase, 2500)
    1.25 +UserMessages::UserMessages()
    1.26 +#ifndef USE_PROTOBUF_USERMESSAGES
    1.27 +	: m_InterceptBuffer(m_pBase, 2500)
    1.28  {
    1.29  	m_Names = sm_trie_create();
    1.30 +#else
    1.31 +	: m_InterceptBuffer(NULL)
    1.32 +{
    1.33 +#endif
    1.34  	m_HookCount = 0;
    1.35  	m_InExec = false;
    1.36  	m_InHook = false;
    1.37 @@ -53,7 +67,9 @@
    1.38  
    1.39  UserMessages::~UserMessages()
    1.40  {
    1.41 +#ifndef USE_PROTOBUF_USERMESSAGES
    1.42  	sm_trie_destroy(m_Names);
    1.43 +#endif
    1.44  
    1.45  	CStack<ListenerInfo *>::iterator iter;
    1.46  	for (iter=m_FreeListeners.begin(); iter!=m_FreeListeners.end(); iter++)
    1.47 @@ -65,8 +81,10 @@
    1.48  
    1.49  void UserMessages::OnSourceModStartup(bool late)
    1.50  {
    1.51 +#ifndef USE_PROTOBUF_USERMESSAGES
    1.52  	/* -1 means SourceMM was unable to get the user message list */
    1.53  	m_FallbackSearch = (g_SMAPI->GetUserMessageCount() == -1);
    1.54 +#endif
    1.55  }
    1.56  
    1.57  void UserMessages::OnSourceModAllInitialized()
    1.58 @@ -78,16 +96,25 @@
    1.59  {
    1.60  	if (m_HookCount)
    1.61  	{
    1.62 +#if SOURCE_ENGINE == SE_CSGO
    1.63 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
    1.64 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
    1.65 +#else
    1.66  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
    1.67  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
    1.68  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
    1.69  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
    1.70 +#endif
    1.71  	}
    1.72  	m_HookCount = 0;
    1.73  }
    1.74  
    1.75  int UserMessages::GetMessageIndex(const char *msg)
    1.76  {
    1.77 +#if SOURCE_ENGINE == SE_CSGO
    1.78 +	// Can split this per engine and/or game later
    1.79 +	return g_Cstrike15UsermessageHelpers.GetIndex(msg);
    1.80 +#else
    1.81  	int msgid;
    1.82  
    1.83  	if (!sm_trie_retrieve(m_Names, msg, reinterpret_cast<void **>(&msgid)))
    1.84 @@ -118,10 +145,19 @@
    1.85  	}
    1.86  
    1.87  	return msgid;
    1.88 +#endif
    1.89  }
    1.90  
    1.91  bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) const
    1.92  {
    1.93 +#if SOURCE_ENGINE == SE_CSGO
    1.94 +	const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
    1.95 +	if (!pszName)
    1.96 +		return false;
    1.97 +
    1.98 +	strncopy(buffer, pszName, maxlength);
    1.99 +	return true;
   1.100 +#else
   1.101  	if (m_FallbackSearch)
   1.102  	{
   1.103  		int size;
   1.104 @@ -137,10 +173,14 @@
   1.105  	}
   1.106  
   1.107  	return false;
   1.108 +#endif
   1.109  }
   1.110  
   1.111 -bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
   1.112 +bf_write *UserMessages::StartBitBufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
   1.113  {
   1.114 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.115 +	return NULL;
   1.116 +#else
   1.117  	bf_write *buffer;
   1.118  
   1.119  	if (m_InExec || m_InHook)
   1.120 @@ -182,6 +222,68 @@
   1.121  	}
   1.122  
   1.123  	return buffer;
   1.124 +#endif // USE_PROTOBUF_USERMESSAGES
   1.125 +}
   1.126 +
   1.127 +google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
   1.128 +{
   1.129 +#ifndef USE_PROTOBUF_USERMESSAGES
   1.130 +	return NULL;
   1.131 +#else
   1.132 +	protobuf::Message *buffer;
   1.133 +
   1.134 +	if (m_InExec || m_InHook)
   1.135 +	{
   1.136 +		return NULL;
   1.137 +	}
   1.138 +	if (msg_id < 0 || msg_id >= 255)
   1.139 +	{
   1.140 +		return NULL;
   1.141 +	}
   1.142 +
   1.143 +	m_CurId = msg_id;
   1.144 +	m_CellRecFilter.Initialize(players, playersNum);
   1.145 +
   1.146 +	m_CurFlags = flags;
   1.147 +	if (m_CurFlags & USERMSG_INITMSG)
   1.148 +	{
   1.149 +		m_CellRecFilter.SetToInit(true);
   1.150 +	}
   1.151 +	if (m_CurFlags & USERMSG_RELIABLE)
   1.152 +	{
   1.153 +		m_CellRecFilter.SetToReliable(true);
   1.154 +	}
   1.155 +
   1.156 +	m_InExec = true;
   1.157 +
   1.158 +	if (m_CurFlags & USERMSG_BLOCKHOOKS)
   1.159 +	{
   1.160 +		// direct message creation, return buffer "from engine". keep track
   1.161 +		m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
   1.162 +		buffer = m_FakeEngineBuffer;
   1.163 +	} else {
   1.164 +		protobuf::Message *msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
   1.165 +		switch (m_FakeMetaRes)
   1.166 +		{
   1.167 +		case MRES_IGNORED:
   1.168 +		case MRES_HANDLED:
   1.169 +			m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
   1.170 +			buffer = m_FakeEngineBuffer;
   1.171 +			break;		
   1.172 +
   1.173 +		case MRES_OVERRIDE:
   1.174 +			m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_id)->New();
   1.175 +		// fallthrough
   1.176 +		case MRES_SUPERCEDE:
   1.177 +			buffer = msg;
   1.178 +			break;
   1.179 +		}
   1.180 +		
   1.181 +		OnStartMessage_Post(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, g_SMAPI->GetUserMessage(msg_id));
   1.182 +	}
   1.183 +
   1.184 +	return buffer;
   1.185 +#endif // USE_PROTOBUF_USERMESSAGES
   1.186  }
   1.187  
   1.188  bool UserMessages::EndMessage()
   1.189 @@ -191,12 +293,37 @@
   1.190  		return false;
   1.191  	}
   1.192  
   1.193 +#if SOURCE_ENGINE == SE_CSGO
   1.194 +	if (m_CurFlags & USERMSG_BLOCKHOOKS)
   1.195 +	{
   1.196 +		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
   1.197 +		delete m_FakeEngineBuffer;
   1.198 +		m_FakeEngineBuffer = NULL;
   1.199 +	} else {
   1.200 +		OnMessageEnd_Pre();
   1.201 +
   1.202 +		switch (m_FakeMetaRes)
   1.203 +		{
   1.204 +		case MRES_IGNORED:
   1.205 +		case MRES_HANDLED:
   1.206 +		case MRES_OVERRIDE:
   1.207 +			engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
   1.208 +			delete m_FakeEngineBuffer;
   1.209 +			m_FakeEngineBuffer = NULL;
   1.210 +			break;
   1.211 +		//case MRES_SUPERCEDE:
   1.212 +		}
   1.213 +
   1.214 +		OnMessageEnd_Post();
   1.215 +	}
   1.216 +#else
   1.217  	if (m_CurFlags & USERMSG_BLOCKHOOKS)
   1.218  	{
   1.219  		ENGINE_CALL(MessageEnd)();
   1.220  	} else {
   1.221  		engine->MessageEnd();
   1.222  	}
   1.223 +#endif // SE_CSGO
   1.224  
   1.225  	m_InExec = false;
   1.226  	m_CurFlags = 0;
   1.227 @@ -205,31 +332,60 @@
   1.228  	return true;
   1.229  }
   1.230  
   1.231 +UserMessageType UserMessages::GetUserMessageType() const
   1.232 +{
   1.233 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.234 +	return UM_Protobuf;
   1.235 +#else
   1.236 +	return UM_BitBuf;
   1.237 +#endif
   1.238 +}
   1.239 +
   1.240  bool UserMessages::HookUserMessage2(int msg_id,
   1.241  									IUserMessageListener *pListener,
   1.242  									bool intercept)
   1.243  {
   1.244 -	return InternalHook(msg_id, pListener, intercept, true);
   1.245 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.246 +	return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
   1.247 +#else
   1.248 +	return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
   1.249 +#endif
   1.250  }
   1.251  
   1.252  bool UserMessages::UnhookUserMessage2(int msg_id,
   1.253  									  IUserMessageListener *pListener,
   1.254  									  bool intercept)
   1.255  {
   1.256 -	return InternalUnhook(msg_id, pListener, intercept, true);
   1.257 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.258 +	return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, true);
   1.259 +#else
   1.260 +	return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, true);
   1.261 +#endif
   1.262  }
   1.263  
   1.264  bool UserMessages::HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
   1.265  {
   1.266 -	return InternalHook(msg_id, pListener, intercept, false);
   1.267 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.268 +	return InternalHook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
   1.269 +#else
   1.270 +	return InternalHook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
   1.271 +#endif
   1.272  }
   1.273  
   1.274  bool UserMessages::UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept)
   1.275  {	
   1.276 -	return InternalUnhook(msg_id, pListener, intercept, false);
   1.277 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.278 +	return InternalUnhook(msg_id, (IProtobufUserMessageListener *)pListener, intercept, false);
   1.279 +#else
   1.280 +	return InternalUnhook(msg_id, (IBitBufUserMessageListener *)pListener, intercept, false);
   1.281 +#endif
   1.282  }
   1.283  
   1.284 -bool UserMessages::InternalHook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew)
   1.285 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.286 +bool UserMessages::InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
   1.287 +#else
   1.288 +bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
   1.289 +#endif
   1.290  {
   1.291  	if (msg_id < 0 || msg_id >= 255)
   1.292  	{
   1.293 @@ -252,10 +408,15 @@
   1.294  
   1.295  	if (!m_HookCount++)
   1.296  	{
   1.297 +#if SOURCE_ENGINE == SE_CSGO
   1.298 +		SH_ADD_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
   1.299 +		SH_ADD_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
   1.300 +#else
   1.301  		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
   1.302  		SH_ADD_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
   1.303  		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
   1.304  		SH_ADD_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
   1.305 +#endif
   1.306  	}
   1.307  
   1.308  	if (intercept)
   1.309 @@ -268,7 +429,11 @@
   1.310  	return true;
   1.311  }
   1.312  
   1.313 -bool UserMessages::InternalUnhook(int msg_id, IUserMessageListener *pListener, bool intercept, bool isNew)
   1.314 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.315 +bool UserMessages::InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew)
   1.316 +#else
   1.317 +bool UserMessages::InternalUnhook(int msg_id, IBitBufUserMessageListener *pListener, bool intercept, bool isNew)
   1.318 +#endif
   1.319  {
   1.320  	MsgList *pList;
   1.321  	MsgIter iter;
   1.322 @@ -309,14 +474,167 @@
   1.323  {
   1.324  	if (--m_HookCount == 0)
   1.325  	{
   1.326 +#if SOURCE_ENGINE == SE_CSGO
   1.327 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Pre, false);
   1.328 +		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, SendUserMessage, engine, this, &UserMessages::OnSendUserMessage_Post, true);
   1.329 +#else
   1.330  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Pre, false);
   1.331  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, UserMessageBegin, engine, this, &UserMessages::OnStartMessage_Post, true);
   1.332  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Pre, false);
   1.333  		SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, MessageEnd, engine, this, &UserMessages::OnMessageEnd_Post, true);
   1.334 +#endif
   1.335  	}
   1.336  }
   1.337  
   1.338 -#if SOURCE_ENGINE >= SE_LEFT4DEAD
   1.339 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.340 +// Unlike protobuf's Message::CopyFrom:
   1.341 +// - Does not require to/from message descriptors to be identical.
   1.342 +// - Fields are copied by name, rather than index.
   1.343 +// - String fields are retrieved for copy with GetStringReference, to avoid destucting libprotobuf std::string in sm.
   1.344 +// - Unknown fields in |from| message are not copied to |to| message.
   1.345 +// - Copying Message fields recursively calls this function, rather than Message::MergeFrom.
   1.346 +static void _CopyProtobufMessage(const protobuf::Message &from, protobuf::Message *to)
   1.347 +{
   1.348 +	const protobuf::Descriptor* descriptor = from.GetDescriptor();
   1.349 +
   1.350 +	const protobuf::Reflection* from_reflection = from.GetReflection();
   1.351 +	const protobuf::Reflection* to_reflection = to->GetReflection();
   1.352 +
   1.353 +	protobuf::UnknownFieldSet toUnknownFields;
   1.354 +
   1.355 +	int fromFieldCount = descriptor->field_count();
   1.356 +	for (int i = 0; i < fromFieldCount; i++)
   1.357 +	{
   1.358 +		const protobuf::FieldDescriptor* fromField = descriptor->field(i);
   1.359 +		const protobuf::FieldDescriptor* toField = to->GetDescriptor()->FindFieldByName(fromField->name());
   1.360 +
   1.361 +		// This will stripped new fields off of intercepted usermessages.
   1.362 +		// TODO: fix that.
   1.363 +		if (!toField)
   1.364 +		{
   1.365 +			continue;
   1.366 +		}
   1.367 +
   1.368 +		if (fromField->is_repeated())
   1.369 +		{
   1.370 +			int count = from_reflection->FieldSize(from, fromField);
   1.371 +			for (int j = 0; j < count; j++)
   1.372 +			{
   1.373 +				switch (fromField->cpp_type())
   1.374 +				{
   1.375 +#define HANDLE_TYPE(CPPTYPE, METHOD)                                           \
   1.376 +				case protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE:             \
   1.377 +					to_reflection->Add##METHOD(to, toField,                    \
   1.378 +					from_reflection->GetRepeated##METHOD(from, fromField, j)); \
   1.379 +					break;
   1.380 +				HANDLE_TYPE(INT32 , Int32 );
   1.381 +				HANDLE_TYPE(INT64 , Int64 );
   1.382 +				HANDLE_TYPE(UINT32, UInt32);
   1.383 +				HANDLE_TYPE(UINT64, UInt64);
   1.384 +				HANDLE_TYPE(FLOAT , Float );
   1.385 +				HANDLE_TYPE(DOUBLE, Double);
   1.386 +				HANDLE_TYPE(BOOL  , Bool  );
   1.387 +				HANDLE_TYPE(ENUM  , Enum  );
   1.388 +#undef HANDLE_TYPE
   1.389 +				case protobuf::FieldDescriptor::CPPTYPE_STRING:
   1.390 +					{
   1.391 +						std::string buffer;
   1.392 +						to_reflection->AddString(to, toField,
   1.393 +							from_reflection->GetRepeatedStringReference(from, fromField, j, &buffer));
   1.394 +					}
   1.395 +					break;
   1.396 +				case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
   1.397 +					_CopyProtobufMessage(
   1.398 +						from_reflection->GetRepeatedMessage(from, fromField, j),
   1.399 +						to_reflection->AddMessage(to, toField)
   1.400 +						);
   1.401 +					break;
   1.402 +				}
   1.403 +			}
   1.404 +		}
   1.405 +		else
   1.406 +		{
   1.407 +			switch (fromField->cpp_type())
   1.408 +			{
   1.409 +#define HANDLE_TYPE(CPPTYPE, METHOD)                            \
   1.410 +			case protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE:  \
   1.411 +				to_reflection->Set##METHOD(to, toField,         \
   1.412 +				from_reflection->Get##METHOD(from, fromField)); \
   1.413 +				break;
   1.414 +			HANDLE_TYPE(INT32 , Int32 );
   1.415 +			HANDLE_TYPE(INT64 , Int64 );
   1.416 +			HANDLE_TYPE(UINT32, UInt32);
   1.417 +			HANDLE_TYPE(UINT64, UInt64);
   1.418 +			HANDLE_TYPE(FLOAT , Float );
   1.419 +			HANDLE_TYPE(DOUBLE, Double);
   1.420 +			HANDLE_TYPE(BOOL  , Bool  );
   1.421 +			HANDLE_TYPE(ENUM  , Enum  );
   1.422 +#undef HANDLE_TYPE
   1.423 +			case protobuf::FieldDescriptor::CPPTYPE_STRING:
   1.424 +				{
   1.425 +					std::string buffer;
   1.426 +					to_reflection->SetString(to, toField,
   1.427 +						from_reflection->GetStringReference(from, fromField, &buffer));
   1.428 +				}
   1.429 +				break;
   1.430 +			case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
   1.431 +				_CopyProtobufMessage(
   1.432 +					from_reflection->GetMessage(from, fromField),
   1.433 +					to_reflection->MutableMessage(to, toField)
   1.434 +					);
   1.435 +				break;
   1.436 +			}
   1.437 +		}
   1.438 +	}
   1.439 +}
   1.440 +#endif
   1.441 +
   1.442 +#if SOURCE_ENGINE == SE_CSGO
   1.443 +void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
   1.444 +{
   1.445 +	OnStartMessage_Pre(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
   1.446 +	if (m_FakeMetaRes == MRES_SUPERCEDE)
   1.447 +	{
   1.448 +		_CopyProtobufMessage(msg, m_InterceptBuffer);
   1.449 +	}
   1.450 +	else
   1.451 +	{
   1.452 +		OnStartMessage_Post(&filter, msg_type, g_Cstrike15UsermessageHelpers.GetName(msg_type));
   1.453 +	}
   1.454 +
   1.455 +	OnMessageEnd_Pre();
   1.456 +	if (m_FakeMetaRes == MRES_SUPERCEDE)
   1.457 +		RETURN_META(MRES_SUPERCEDE);
   1.458 +
   1.459 +	RETURN_META(MRES_IGNORED);
   1.460 +}
   1.461 +
   1.462 +void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
   1.463 +{
   1.464 +	OnMessageEnd_Post();
   1.465 +	RETURN_META(MRES_IGNORED);
   1.466 +}
   1.467 +#endif
   1.468 +
   1.469 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.470 +#define UM_RETURN_META_VALUE(res, val) \
   1.471 +	m_FakeMetaRes = res;               \
   1.472 +	return val;
   1.473 +
   1.474 +#define UM_RETURN_META(res)            \
   1.475 +	m_FakeMetaRes = res;               \
   1.476 +	return;
   1.477 +#else
   1.478 +#define UM_RETURN_META_VALUE(res, val) \
   1.479 +	RETURN_META_VALUE(res, val)
   1.480 +
   1.481 +#define UM_RETURN_META(res)            \
   1.482 +	RETURN_META(res)
   1.483 +#endif
   1.484 +
   1.485 +#if SOURCE_ENGINE == SE_CSGO
   1.486 +protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
   1.487 +#elif SOURCE_ENGINE >= SE_LEFT4DEAD
   1.488  bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
   1.489  #else
   1.490  bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type)
   1.491 @@ -329,7 +647,7 @@
   1.492  		|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
   1.493  	{
   1.494  		m_InHook = false;
   1.495 -		RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.496 +		UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.497  	}
   1.498  
   1.499  	m_CurId = msg_type;
   1.500 @@ -339,14 +657,23 @@
   1.501  
   1.502  	if (!is_intercept_empty)
   1.503  	{
   1.504 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.505 +		if (m_InterceptBuffer)
   1.506 +			delete m_InterceptBuffer;
   1.507 +		m_InterceptBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
   1.508 +		UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
   1.509 +#else
   1.510  		m_InterceptBuffer.Reset();
   1.511 -		RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
   1.512 +		UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
   1.513 +#endif
   1.514  	}
   1.515  
   1.516 -	RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.517 +	UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.518  }
   1.519  
   1.520 -#if SOURCE_ENGINE >= SE_LEFT4DEAD
   1.521 +#if SOURCE_ENGINE == SE_CSGO
   1.522 +protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
   1.523 +#elif SOURCE_ENGINE >= SE_LEFT4DEAD
   1.524  bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
   1.525  #else
   1.526  bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type)
   1.527 @@ -354,19 +681,24 @@
   1.528  {
   1.529  	if (!m_InHook)
   1.530  	{
   1.531 -		RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.532 +		UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.533  	}
   1.534  
   1.535 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.536 +	m_FakeEngineBuffer = g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
   1.537 +	m_OrigBuffer = m_FakeEngineBuffer;
   1.538 +#else
   1.539  	m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
   1.540 +#endif
   1.541  
   1.542 -	RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.543 +	UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.544  }
   1.545  
   1.546  void UserMessages::OnMessageEnd_Post()
   1.547  {
   1.548  	if (!m_InHook)
   1.549  	{
   1.550 -		RETURN_META(MRES_IGNORED);
   1.551 +		UM_RETURN_META(MRES_IGNORED);
   1.552  	}
   1.553  
   1.554  	MsgList *pList;
   1.555 @@ -434,7 +766,7 @@
   1.556  {
   1.557  	if (!m_InHook)
   1.558  	{
   1.559 -		RETURN_META(MRES_IGNORED);
   1.560 +		UM_RETURN_META(MRES_IGNORED);
   1.561  	}
   1.562  
   1.563  	MsgList *pList;
   1.564 @@ -450,7 +782,11 @@
   1.565  	{
   1.566  		pInfo = (*iter);
   1.567  		pInfo->IsHooked = true;
   1.568 +#ifdef USE_PROTOBUF_USERMESSAGES
   1.569 +		res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
   1.570 +#else
   1.571  		res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
   1.572 +#endif
   1.573  
   1.574  		intercepted = true;
   1.575  
   1.576 @@ -498,8 +834,12 @@
   1.577  
   1.578  	if (!handled && intercepted)
   1.579  	{
   1.580 +#if SOURCE_ENGINE == SE_CSGO
   1.581 +		ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
   1.582 +		delete m_InterceptBuffer;
   1.583 +		m_InterceptBuffer = NULL;
   1.584 +#else
   1.585  		bf_write *engine_bfw;
   1.586 -
   1.587  #if SOURCE_ENGINE >= SE_LEFT4DEAD
   1.588  		engine_bfw = ENGINE_CALL(UserMessageBegin)(m_CurRecFilter, m_CurId, g_SMAPI->GetUserMessage(m_CurId));
   1.589  #else
   1.590 @@ -508,6 +848,7 @@
   1.591  		m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
   1.592  		engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
   1.593  		ENGINE_CALL(MessageEnd)();
   1.594 +#endif // SE_CSGO
   1.595  	}
   1.596  
   1.597  	pList = &m_msgHooks[m_CurId];
   1.598 @@ -529,8 +870,8 @@
   1.599  		iter++;
   1.600  	}
   1.601  
   1.602 -	RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
   1.603 +	UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
   1.604  supercede:
   1.605  	m_BlockEndPost = true;
   1.606 -	RETURN_META(MRES_SUPERCEDE);
   1.607 +	UM_RETURN_META(MRES_SUPERCEDE);
   1.608  }