core/UserMessagePBHelpers.h
author Nicholas Hastings <skamonkey@gmail.com>
Tue Jan 22 21:43:12 2013 -0500 (2013-01-22)
changeset 3743 a98686a77974
child 3746 ba9a19449509
permissions -rw-r--r--
Added initial support for protobuf usermessages on CS:GO (bug 5579, r=asherkin).
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2013 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #ifndef _INCLUDE_SOURCEMOD_SMPBMESSAGE_H_
    33 #define _INCLUDE_SOURCEMOD_SMPBMESSAGE_H_
    34 
    35 #include <sh_list.h>
    36 #include <google/protobuf/descriptor.h>
    37 
    38 #define GETCHECK_FIELD() \
    39 	const protobuf::FieldDescriptor *field = msg->GetDescriptor()->FindFieldByName(pszFieldName); \
    40 	if (!field)       \
    41 	{                 \
    42 		return false; \
    43 	}
    44 
    45 #define CHECK_FIELD_TYPE(type) \
    46 	if (field->cpp_type() != protobuf::FieldDescriptor::CPPTYPE_##type) \
    47 	{                 \
    48 		return false; \
    49 	}
    50 
    51 #define CHECK_FIELD_TYPE2(type1, type2) \
    52 	protobuf::FieldDescriptor::CppType fieldType = field->cpp_type(); \
    53 	if (fieldType != protobuf::FieldDescriptor::CPPTYPE_##type1       \
    54 		&& fieldType != protobuf::FieldDescriptor::CPPTYPE_##type2) \
    55 	{                 \
    56 		return false; \
    57 	}
    58 
    59 #define CHECK_FIELD_REPEATED() \
    60 	if (field->label() != protobuf::FieldDescriptor::LABEL_REPEATED) \
    61 	{                 \
    62 		return false; \
    63 	}
    64 
    65 #define CHECK_FIELD_NOT_REPEATED() \
    66 	if (field->label() == protobuf::FieldDescriptor::LABEL_REPEATED) \
    67 	{                 \
    68 		return false; \
    69 	}
    70 
    71 #define CHECK_REPEATED_ELEMENT(idx) \
    72 	int elemCount = msg->GetReflection()->FieldSize(*msg, field); \
    73 	if (elemCount == 0 || idx >= elemCount || idx <= 0)       \
    74 	{                                                         \
    75 		return false;                                         \
    76 	}
    77 
    78 typedef List<Handle_t> PBHandleList;
    79 
    80 class SMProtobufMessage
    81 {
    82 public:
    83 	SMProtobufMessage( protobuf::Message *message )
    84 	{
    85 		msg = message;
    86 	}
    87 
    88 	~SMProtobufMessage()
    89 	{
    90 		PBHandleList::iterator iter = childHandles.begin();
    91 		while (iter != childHandles.end())
    92 		{
    93 			Handle_t &hndl = (*iter);
    94 			HandleSecurity sec;
    95 			sec.pIdentity = g_pCoreIdent;
    96 			g_HandleSys.FreeHandle(hndl, &sec);
    97 			iter = childHandles.erase(iter);
    98 		}
    99 	}
   100 
   101 	inline void AddChildHandle(Handle_t hndl)
   102 	{
   103 		childHandles.push_back(hndl);
   104 	}
   105 
   106 	inline protobuf::Message *GetProtobufMessage()
   107 	{
   108 		return msg;
   109 	}
   110 
   111 	inline bool GetInt32(const char *pszFieldName, int32 *out)
   112 	{
   113 		GETCHECK_FIELD();
   114 		CHECK_FIELD_TYPE(INT32);
   115 		CHECK_FIELD_NOT_REPEATED();
   116 
   117 		*out = msg->GetReflection()->GetInt32(*msg, field);
   118 		return true;	
   119 	}
   120 
   121 	inline bool SetInt32(const char *pszFieldName, int32 value)
   122 	{
   123 		GETCHECK_FIELD();
   124 		CHECK_FIELD_TYPE(INT32);
   125 		CHECK_FIELD_NOT_REPEATED();
   126 
   127 		msg->GetReflection()->SetInt32(msg, field, value);
   128 		return true;
   129 	}
   130 
   131 	inline bool GetRepeatedInt32(const char *pszFieldName, int index, int32 *out)
   132 	{
   133 		GETCHECK_FIELD();
   134 		CHECK_FIELD_TYPE(INT32);
   135 		CHECK_FIELD_REPEATED();
   136 		CHECK_REPEATED_ELEMENT(index);
   137 		
   138 		*out = msg->GetReflection()->GetRepeatedInt32(*msg, field, index);
   139 		return true;
   140 	}
   141 
   142 	inline bool AddInt32(const char *pszFieldName, int32 value)
   143 	{
   144 		GETCHECK_FIELD();
   145 		CHECK_FIELD_TYPE(INT32);
   146 		CHECK_FIELD_REPEATED();
   147 
   148 		msg->GetReflection()->AddInt32(msg, field, value);
   149 		return true;
   150 	}
   151 
   152 	inline bool GetInt64(const char *pszFieldName, int64 *out)
   153 	{
   154 		GETCHECK_FIELD();
   155 		CHECK_FIELD_TYPE(INT64);
   156 		CHECK_FIELD_NOT_REPEATED();
   157 
   158 		*out = msg->GetReflection()->GetInt64(*msg, field);
   159 		return true;	
   160 	}
   161 
   162 	inline bool SetInt64(const char *pszFieldName, int64 value)
   163 	{
   164 		GETCHECK_FIELD();
   165 		CHECK_FIELD_TYPE(INT64);
   166 		CHECK_FIELD_NOT_REPEATED();
   167 
   168 		msg->GetReflection()->SetInt64(msg, field, value);
   169 		return true;
   170 	}
   171 
   172 	inline bool GetRepeatedInt64(const char *pszFieldName, int index, int64 *out)
   173 	{
   174 		GETCHECK_FIELD();
   175 		CHECK_FIELD_TYPE(INT64);
   176 		CHECK_FIELD_REPEATED();
   177 		CHECK_REPEATED_ELEMENT(index);
   178 		
   179 		*out = msg->GetReflection()->GetRepeatedInt64(*msg, field, index);
   180 		return true;
   181 	}
   182 
   183 	inline bool AddInt64(const char *pszFieldName, int64 value)
   184 	{
   185 		GETCHECK_FIELD();
   186 		CHECK_FIELD_TYPE(INT64);
   187 		CHECK_FIELD_REPEATED();
   188 
   189 		msg->GetReflection()->AddInt64(msg, field, value);
   190 		return true;
   191 	}
   192 
   193 	inline bool GetUInt32(const char *pszFieldName, uint32 *out)
   194 	{
   195 		GETCHECK_FIELD();
   196 		CHECK_FIELD_TYPE(UINT32);
   197 		CHECK_FIELD_NOT_REPEATED();
   198 
   199 		*out = msg->GetReflection()->GetUInt32(*msg, field);
   200 		return true;	
   201 	}
   202 
   203 	inline bool SetUInt32(const char *pszFieldName, uint32 value)
   204 	{
   205 		GETCHECK_FIELD();
   206 		CHECK_FIELD_TYPE(UINT32);
   207 		CHECK_FIELD_NOT_REPEATED();
   208 
   209 		msg->GetReflection()->SetUInt32(msg, field, value);
   210 		return true;
   211 	}
   212 
   213 	inline bool GetRepeatedUInt32(const char *pszFieldName, int index, uint32 *out)
   214 	{
   215 		GETCHECK_FIELD();
   216 		CHECK_FIELD_TYPE(UINT32);
   217 		CHECK_FIELD_REPEATED();
   218 		CHECK_REPEATED_ELEMENT(index);
   219 		
   220 		*out = msg->GetReflection()->GetRepeatedUInt32(*msg, field, index);
   221 		return true;
   222 	}
   223 
   224 	inline bool AddUInt32(const char *pszFieldName, uint32 value)
   225 	{
   226 		GETCHECK_FIELD();
   227 		CHECK_FIELD_TYPE(UINT32);
   228 		CHECK_FIELD_REPEATED();
   229 
   230 		msg->GetReflection()->AddUInt32(msg, field, value);
   231 		return true;
   232 	}
   233 
   234 	inline bool GetUInt64(const char *pszFieldName, uint64 *out)
   235 	{
   236 		GETCHECK_FIELD();
   237 		CHECK_FIELD_TYPE(UINT64);
   238 		CHECK_FIELD_NOT_REPEATED();
   239 
   240 		*out = msg->GetReflection()->GetUInt64(*msg, field);
   241 		return true;	
   242 	}
   243 
   244 	inline bool SetUInt64(const char *pszFieldName, uint64 value)
   245 	{
   246 		GETCHECK_FIELD();
   247 		CHECK_FIELD_TYPE(UINT64);
   248 		CHECK_FIELD_NOT_REPEATED();
   249 
   250 		msg->GetReflection()->SetUInt64(msg, field, value);
   251 		return true;
   252 	}
   253 
   254 	inline bool GetRepeatedUInt64(const char *pszFieldName, int index, uint64 *out)
   255 	{
   256 		GETCHECK_FIELD();
   257 		CHECK_FIELD_TYPE(UINT64);
   258 		CHECK_FIELD_REPEATED();
   259 		CHECK_REPEATED_ELEMENT(index);
   260 		
   261 		*out = msg->GetReflection()->GetRepeatedUInt64(*msg, field, index);
   262 		return true;
   263 	}
   264 
   265 	inline bool AddUInt64(const char *pszFieldName, uint64 value)
   266 	{
   267 		GETCHECK_FIELD();
   268 		CHECK_FIELD_TYPE(UINT64);
   269 		CHECK_FIELD_REPEATED();
   270 
   271 		msg->GetReflection()->AddUInt32(msg, field, value);
   272 		return true;
   273 	}
   274 
   275 	inline bool GetInt32OrUnsigned(const char *pszFieldName, int32 *out)
   276 	{
   277 		GETCHECK_FIELD();
   278 		CHECK_FIELD_TYPE2(INT32, UINT32);
   279 		CHECK_FIELD_NOT_REPEATED();
   280 
   281 		if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT32)
   282 			*out = (int32)msg->GetReflection()->GetUInt32(*msg, field);
   283 		else
   284 			*out = msg->GetReflection()->GetInt32(*msg, field);
   285 
   286 		return true;	
   287 	}
   288 
   289 	inline bool SetInt32OrUnsigned(const char *pszFieldName, int32 value)
   290 	{
   291 		GETCHECK_FIELD();
   292 		CHECK_FIELD_TYPE2(INT32, UINT32);
   293 		CHECK_FIELD_NOT_REPEATED();
   294 
   295 		if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT32)
   296 			msg->GetReflection()->SetUInt32(msg, field, (uint32)value);
   297 		else
   298 			msg->GetReflection()->SetInt32(msg, field, value);
   299 
   300 		return true;
   301 	}
   302 
   303 	inline bool GetRepeatedInt32OrUnsigned(const char *pszFieldName, int index, int32 *out)
   304 	{
   305 		GETCHECK_FIELD();
   306 		CHECK_FIELD_TYPE2(INT32, UINT32);
   307 		CHECK_FIELD_REPEATED();
   308 		CHECK_REPEATED_ELEMENT(index);
   309 		
   310 		if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT32)
   311 			*out = (int32)msg->GetReflection()->GetRepeatedUInt32(*msg, field, index);
   312 		else
   313 			*out = msg->GetReflection()->GetRepeatedInt32(*msg, field, index);
   314 
   315 		return true;
   316 	}
   317 
   318 	inline bool AddInt32OrUnsigned(const char *pszFieldName, int32 value)
   319 	{
   320 		GETCHECK_FIELD();
   321 		CHECK_FIELD_TYPE2(INT32, UINT32);
   322 		CHECK_FIELD_REPEATED();
   323 
   324 		if (fieldType == protobuf::FieldDescriptor::CPPTYPE_UINT32)
   325 			msg->GetReflection()->AddUInt32(msg, field, (uint32)value);
   326 		else
   327 			msg->GetReflection()->AddInt32(msg, field, value);
   328 
   329 		return true;
   330 	}
   331 
   332 	inline bool GetBool(const char *pszFieldName, bool *out)
   333 	{
   334 		GETCHECK_FIELD();
   335 		CHECK_FIELD_TYPE(BOOL);
   336 		CHECK_FIELD_NOT_REPEATED();
   337 
   338 		*out = msg->GetReflection()->GetBool(*msg, field);
   339 		return true;	
   340 	}
   341 
   342 	inline bool SetBool(const char *pszFieldName, bool value)
   343 	{
   344 		GETCHECK_FIELD();
   345 		CHECK_FIELD_TYPE(BOOL);
   346 		CHECK_FIELD_NOT_REPEATED();
   347 
   348 		msg->GetReflection()->SetBool(msg, field, value);
   349 		return true;
   350 	}
   351 
   352 	inline bool GetRepeatedBool(const char *pszFieldName, int index, bool *out)
   353 	{
   354 		GETCHECK_FIELD();
   355 		CHECK_FIELD_TYPE(BOOL);
   356 		CHECK_FIELD_REPEATED();
   357 		CHECK_REPEATED_ELEMENT(index);
   358 		
   359 		*out = msg->GetReflection()->GetRepeatedBool(*msg, field, index);
   360 		return true;
   361 	}
   362 
   363 	inline bool AddBool(const char *pszFieldName, bool value)
   364 	{
   365 		GETCHECK_FIELD();
   366 		CHECK_FIELD_TYPE(BOOL);
   367 		CHECK_FIELD_REPEATED();
   368 
   369 		msg->GetReflection()->AddBool(msg, field, value);
   370 		return true;
   371 	}
   372 
   373 	inline bool GetFloat(const char *pszFieldName, float *out)
   374 	{
   375 		GETCHECK_FIELD();
   376 		CHECK_FIELD_TYPE(FLOAT);
   377 		CHECK_FIELD_NOT_REPEATED();
   378 
   379 		*out = msg->GetReflection()->GetFloat(*msg, field);
   380 		return true;	
   381 	}
   382 
   383 	inline bool SetFloat(const char *pszFieldName, float value)
   384 	{
   385 		GETCHECK_FIELD();
   386 		CHECK_FIELD_TYPE(FLOAT);
   387 		CHECK_FIELD_NOT_REPEATED();
   388 
   389 		msg->GetReflection()->SetFloat(msg, field, value);
   390 		return true;
   391 	}
   392 
   393 	inline bool GetRepeatedFloat(const char *pszFieldName, int index, float *out)
   394 	{
   395 		GETCHECK_FIELD();
   396 		CHECK_FIELD_TYPE(FLOAT);
   397 		CHECK_FIELD_REPEATED();
   398 		CHECK_REPEATED_ELEMENT(index);
   399 		
   400 		*out = msg->GetReflection()->GetRepeatedFloat(*msg, field, index);
   401 		return true;
   402 	}
   403 
   404 	inline bool AddFloat(const char *pszFieldName, float value)
   405 	{
   406 		GETCHECK_FIELD();
   407 		CHECK_FIELD_TYPE(FLOAT);
   408 		CHECK_FIELD_REPEATED();
   409 
   410 		msg->GetReflection()->AddFloat(msg, field, value);
   411 		return true;
   412 	}
   413 
   414 	inline bool GetDouble(const char *pszFieldName, double *out)
   415 	{
   416 		GETCHECK_FIELD();
   417 		CHECK_FIELD_TYPE(DOUBLE);
   418 		CHECK_FIELD_NOT_REPEATED();
   419 
   420 		*out = msg->GetReflection()->GetDouble(*msg, field);
   421 		return true;	
   422 	}
   423 
   424 	inline bool SetDouble(const char *pszFieldName, double value)
   425 	{
   426 		GETCHECK_FIELD();
   427 		CHECK_FIELD_TYPE(DOUBLE);
   428 		CHECK_FIELD_NOT_REPEATED();
   429 
   430 		msg->GetReflection()->SetDouble(msg, field, value);
   431 		return true;
   432 	}
   433 
   434 	inline bool GetRepeatedDouble(const char *pszFieldName, int index, double *out)
   435 	{
   436 		GETCHECK_FIELD();
   437 		CHECK_FIELD_TYPE(DOUBLE);
   438 		CHECK_FIELD_REPEATED();
   439 		CHECK_REPEATED_ELEMENT(index);
   440 		
   441 		*out = msg->GetReflection()->GetRepeatedDouble(*msg, field, index);
   442 		return true;
   443 	}
   444 
   445 	inline bool AddDouble(const char *pszFieldName, double value)
   446 	{
   447 		GETCHECK_FIELD();
   448 		CHECK_FIELD_TYPE(DOUBLE);
   449 		CHECK_FIELD_REPEATED();
   450 
   451 		msg->GetReflection()->AddDouble(msg, field, value);
   452 		return true;
   453 	}
   454 
   455 	inline bool GetFloatOrDouble(const char *pszFieldName, float *out)
   456 	{
   457 		GETCHECK_FIELD();
   458 		CHECK_FIELD_TYPE2(FLOAT, DOUBLE);
   459 		CHECK_FIELD_NOT_REPEATED();
   460 
   461 		if (fieldType == protobuf::FieldDescriptor::CPPTYPE_DOUBLE)
   462 			*out = (float)msg->GetReflection()->GetDouble(*msg, field);
   463 		else
   464 			*out = msg->GetReflection()->GetFloat(*msg, field);
   465 
   466 		return true;	
   467 	}
   468 
   469 	inline bool SetFloatOrDouble(const char *pszFieldName, float value)
   470 	{
   471 		GETCHECK_FIELD();
   472 		CHECK_FIELD_TYPE2(FLOAT, DOUBLE);
   473 		CHECK_FIELD_NOT_REPEATED();
   474 
   475 		if (fieldType == protobuf::FieldDescriptor::CPPTYPE_DOUBLE)
   476 			msg->GetReflection()->SetDouble(msg, field, (double)value);
   477 		else
   478 			msg->GetReflection()->SetFloat(msg, field, value);
   479 
   480 		return true;
   481 	}
   482 
   483 	inline bool GetRepeatedFloatOrDouble(const char *pszFieldName, int index, float *out)
   484 	{
   485 		GETCHECK_FIELD();
   486 		CHECK_FIELD_TYPE2(FLOAT, DOUBLE);
   487 		CHECK_FIELD_REPEATED();
   488 		CHECK_REPEATED_ELEMENT(index);
   489 		
   490 		if (fieldType == protobuf::FieldDescriptor::CPPTYPE_DOUBLE)
   491 			*out = (float)msg->GetReflection()->GetRepeatedDouble(*msg, field, index);
   492 		else
   493 			*out = msg->GetReflection()->GetRepeatedFloat(*msg, field, index);
   494 
   495 		return true;
   496 	}
   497 
   498 	inline bool AddFloatOrDouble(const char *pszFieldName, float value)
   499 	{
   500 		GETCHECK_FIELD();
   501 		CHECK_FIELD_TYPE2(FLOAT, DOUBLE);
   502 		CHECK_FIELD_REPEATED();
   503 
   504 		if (fieldType == protobuf::FieldDescriptor::CPPTYPE_DOUBLE)
   505 			msg->GetReflection()->AddDouble(msg, field, (double)value);
   506 		else
   507 			msg->GetReflection()->AddFloat(msg, field, value);
   508 
   509 		return true;
   510 	}
   511 
   512 	inline bool GetString(const char *pszFieldName, char *out, int size)
   513 	{
   514 		GETCHECK_FIELD();
   515 		CHECK_FIELD_TYPE(STRING);
   516 		CHECK_FIELD_NOT_REPEATED();
   517 
   518 		std::string scratch;
   519 		strncopy(out, msg->GetReflection()->GetStringReference(*msg, field, &buffer).c_str(), size);
   520 
   521 		return true;	
   522 	}
   523 
   524 	inline bool SetString(const char *pszFieldName, const char *value)
   525 	{
   526 		GETCHECK_FIELD();
   527 		CHECK_FIELD_TYPE(STRING);
   528 		CHECK_FIELD_NOT_REPEATED();
   529 
   530 		msg->GetReflection()->SetString(msg, field, value);
   531 		return true;
   532 	}
   533 
   534 	inline bool GetRepeatedString(const char *pszFieldName, int index, char *out, int size)
   535 	{
   536 		GETCHECK_FIELD();
   537 		CHECK_FIELD_TYPE(STRING);
   538 		CHECK_FIELD_REPEATED();
   539 		CHECK_REPEATED_ELEMENT(index);
   540 		
   541 		std::string scratch;
   542 		strncopy(out, msg->GetReflection()->GetRepeatedStringReference(*msg, field, index, &scratch).c_str(), size);
   543 
   544 		return true;
   545 	}
   546 
   547 	inline bool AddString(const char *pszFieldName, const char *value)
   548 	{
   549 		GETCHECK_FIELD();
   550 		CHECK_FIELD_TYPE(STRING);
   551 		CHECK_FIELD_REPEATED();
   552 
   553 		msg->GetReflection()->AddString(msg, field, value);
   554 		return true;
   555 	}
   556 
   557 	inline bool GetColor(const char *pszFieldName, Color *out)
   558 	{
   559 		GETCHECK_FIELD();
   560 		CHECK_FIELD_TYPE(MESSAGE);
   561 		CHECK_FIELD_NOT_REPEATED();
   562 
   563 		const CMsgRGBA &msgRGBA = (const CMsgRGBA &)msg->GetReflection()->GetMessage(*msg, field);
   564 		out->SetColor(
   565 			msgRGBA.r(),
   566 			msgRGBA.g(),
   567 			msgRGBA.b(),
   568 			msgRGBA.a()
   569 			);
   570 
   571 		return true;
   572 	}
   573 
   574 	inline bool SetColor(const char *pszFieldName, const Color &value)
   575 	{
   576 		GETCHECK_FIELD();
   577 		CHECK_FIELD_TYPE(MESSAGE);
   578 		CHECK_FIELD_NOT_REPEATED();
   579 
   580 		CMsgRGBA *msgRGBA = (CMsgRGBA *)msg->GetReflection()->MutableMessage(msg, field);
   581 		msgRGBA->set_r(value.r());
   582 		msgRGBA->set_g(value.g());
   583 		msgRGBA->set_b(value.b());
   584 		msgRGBA->set_a(value.a());
   585 
   586 		return true;
   587 	}
   588 
   589 	inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out)
   590 	{
   591 		GETCHECK_FIELD();
   592 		CHECK_FIELD_TYPE(MESSAGE);
   593 		CHECK_FIELD_REPEATED();
   594 		CHECK_REPEATED_ELEMENT(index);
   595 
   596 		const CMsgRGBA &msgRGBA = (const CMsgRGBA &)msg->GetReflection()->GetRepeatedMessage(*msg, field, index);
   597 		out->SetColor(
   598 			msgRGBA.r(),
   599 			msgRGBA.g(),
   600 			msgRGBA.b(),
   601 			msgRGBA.a()
   602 			);
   603 
   604 		return true;
   605 	}
   606 
   607 	inline bool AddColor(const char *pszFieldName, const Color &value)
   608 	{
   609 		GETCHECK_FIELD();
   610 		CHECK_FIELD_TYPE(MESSAGE);
   611 		CHECK_FIELD_REPEATED();
   612 
   613 		CMsgRGBA *msgRGBA = (CMsgRGBA *)msg->GetReflection()->AddMessage(msg, field);
   614 		msgRGBA->set_r(value.r());
   615 		msgRGBA->set_g(value.g());
   616 		msgRGBA->set_b(value.b());
   617 		msgRGBA->set_a(value.a());
   618 
   619 		return true;
   620 	}
   621 
   622 	inline bool GetVector2D(const char *pszFieldName, Vector2D *out)
   623 	{
   624 		GETCHECK_FIELD();
   625 		CHECK_FIELD_TYPE(MESSAGE);
   626 		CHECK_FIELD_NOT_REPEATED();
   627 
   628 		const CMsgVector2D &msgVec2d = (const CMsgVector2D &)msg->GetReflection()->GetMessage(*msg, field);
   629 		out->Init(
   630 			msgVec2d.x(),
   631 			msgVec2d.y()
   632 			);
   633 
   634 		return true;
   635 	}
   636 
   637 	inline bool SetVector2D(const char *pszFieldName, Vector2D &vec)
   638 	{
   639 		GETCHECK_FIELD();
   640 		CHECK_FIELD_TYPE(MESSAGE);
   641 		CHECK_FIELD_NOT_REPEATED();
   642 
   643 		CMsgVector2D *msgVec2d = (CMsgVector2D *)msg->GetReflection()->MutableMessage(msg, field);
   644 		msgVec2d->set_x(vec.x);
   645 		msgVec2d->set_y(vec.y);
   646 
   647 		return true;
   648 	}
   649 
   650 	inline bool GetRepeatedVector2D(const char *pszFieldName, int index, Vector2D *out)
   651 	{
   652 		GETCHECK_FIELD();
   653 		CHECK_FIELD_TYPE(MESSAGE);
   654 		CHECK_FIELD_REPEATED();
   655 		CHECK_REPEATED_ELEMENT(index);
   656 
   657 		const CMsgVector2D &msgVec2d = (const CMsgVector2D &)msg->GetReflection()->GetRepeatedMessage(*msg, field, index);
   658 		out->Init(
   659 			msgVec2d.x(),
   660 			msgVec2d.y()
   661 			);
   662 
   663 		return true;
   664 	}
   665 
   666 	inline bool AddVector2D(const char *pszFieldName, Vector2D &vec)
   667 	{
   668 		GETCHECK_FIELD();
   669 		CHECK_FIELD_TYPE(MESSAGE);
   670 		CHECK_FIELD_REPEATED();
   671 
   672 		CMsgVector2D *msgVec2d = (CMsgVector2D *)msg->GetReflection()->AddMessage(msg, field);
   673 		msgVec2d->set_x(vec.x);
   674 		msgVec2d->set_y(vec.y);
   675 
   676 		return true;
   677 	}
   678 
   679 	inline bool GetVector(const char *pszFieldName, Vector *out)
   680 	{
   681 		GETCHECK_FIELD();
   682 		CHECK_FIELD_TYPE(MESSAGE);
   683 		CHECK_FIELD_NOT_REPEATED();
   684 
   685 		const CMsgVector &msgVec = (const CMsgVector &)msg->GetReflection()->GetMessage(*msg, field);
   686 		out->Init(
   687 			msgVec.x(),
   688 			msgVec.y(),
   689 			msgVec.z()
   690 			);
   691 
   692 		return true;
   693 	}
   694 
   695 	inline bool SetVector(const char *pszFieldName, Vector &vec)
   696 	{
   697 		GETCHECK_FIELD();
   698 		CHECK_FIELD_TYPE(MESSAGE);
   699 		CHECK_FIELD_NOT_REPEATED();
   700 
   701 		CMsgVector *msgVec = (CMsgVector *)msg->GetReflection()->MutableMessage(msg, field);
   702 		msgVec->set_x(vec.x);
   703 		msgVec->set_y(vec.y);
   704 		msgVec->set_z(vec.z);
   705 
   706 		return true;
   707 	}
   708 
   709 	inline bool GetRepeatedVector(const char *pszFieldName, int index, Vector *out)
   710 	{
   711 		GETCHECK_FIELD();
   712 		CHECK_FIELD_TYPE(MESSAGE);
   713 		CHECK_FIELD_REPEATED();
   714 		CHECK_REPEATED_ELEMENT(index);
   715 
   716 		const CMsgVector &msgVec = (const CMsgVector &)msg->GetReflection()->GetRepeatedMessage(*msg, field, index);
   717 		out->Init(
   718 			msgVec.x(),
   719 			msgVec.y(),
   720 			msgVec.z()
   721 			);
   722 
   723 		return true;
   724 	}
   725 
   726 	inline bool AddVector(const char *pszFieldName, Vector &vec)
   727 	{
   728 		GETCHECK_FIELD();
   729 		CHECK_FIELD_TYPE(MESSAGE);
   730 		CHECK_FIELD_REPEATED();
   731 
   732 		CMsgVector *msgVec = (CMsgVector *)msg->GetReflection()->AddMessage(msg, field);
   733 		msgVec->set_x(vec.x);
   734 		msgVec->set_y(vec.y);
   735 		msgVec->set_z(vec.z);
   736 
   737 		return true;
   738 	}
   739 
   740 	inline bool GetQAngle(const char *pszFieldName, QAngle *out)
   741 	{
   742 		GETCHECK_FIELD();
   743 		CHECK_FIELD_TYPE(MESSAGE);
   744 		CHECK_FIELD_NOT_REPEATED();
   745 
   746 		const CMsgQAngle &msgAng = (const CMsgQAngle &)msg->GetReflection()->GetMessage(*msg, field);
   747 		out->Init(
   748 			msgAng.x(),
   749 			msgAng.y(),
   750 			msgAng.z()
   751 			);
   752 
   753 		return true;
   754 	}
   755 
   756 	inline bool SetQAngle(const char *pszFieldName, QAngle &vec)
   757 	{
   758 		GETCHECK_FIELD();
   759 		CHECK_FIELD_TYPE(MESSAGE);
   760 		CHECK_FIELD_NOT_REPEATED();
   761 
   762 		CMsgQAngle *msgAng = (CMsgQAngle *)msg->GetReflection()->MutableMessage(msg, field);
   763 		msgAng->set_x(vec.x);
   764 		msgAng->set_y(vec.y);
   765 		msgAng->set_z(vec.z);
   766 
   767 		return true;
   768 	}
   769 
   770 	inline bool GetRepeatedQAngle(const char *pszFieldName, int index, QAngle *out)
   771 	{
   772 		GETCHECK_FIELD();
   773 		CHECK_FIELD_TYPE(MESSAGE);
   774 		CHECK_FIELD_REPEATED();
   775 		CHECK_REPEATED_ELEMENT(index);
   776 
   777 		const CMsgQAngle &msgAng = (const CMsgQAngle &)msg->GetReflection()->GetRepeatedMessage(*msg, field, index);
   778 		out->Init(
   779 			msgAng.x(),
   780 			msgAng.y(),
   781 			msgAng.z()
   782 			);
   783 
   784 		return true;
   785 	}
   786 
   787 	inline bool AddQAngle(const char *pszFieldName, QAngle &vec)
   788 	{
   789 		GETCHECK_FIELD();
   790 		CHECK_FIELD_TYPE(MESSAGE);
   791 		CHECK_FIELD_REPEATED();
   792 
   793 		CMsgQAngle *msgAng = (CMsgQAngle *)msg->GetReflection()->AddMessage(msg, field);
   794 		msgAng->set_x(vec.x);
   795 		msgAng->set_y(vec.y);
   796 		msgAng->set_z(vec.z);
   797 
   798 		return true;
   799 	}
   800 
   801 	inline bool GetMessage(const char *pszFieldName, protobuf::Message **message)
   802 	{
   803 		GETCHECK_FIELD();
   804 		CHECK_FIELD_TYPE(MESSAGE);
   805 		CHECK_FIELD_NOT_REPEATED();
   806 
   807 		*message = msg->GetReflection()->MutableMessage(msg, field);
   808 
   809 		return true;
   810 	}
   811 
   812 	inline bool GetRepeatedMessage(const char *pszFieldName, int index, const protobuf::Message **message)
   813 	{
   814 		GETCHECK_FIELD();
   815 		CHECK_FIELD_TYPE(MESSAGE);
   816 		CHECK_FIELD_REPEATED();
   817 		CHECK_REPEATED_ELEMENT(index);
   818 
   819 		const protobuf::Message *m = &msg->GetReflection()->GetRepeatedMessage(*msg, field, index);
   820 		*message = m;
   821 
   822 		return true;
   823 	}
   824 
   825 	inline bool AddMessage(const char *pszFieldName, protobuf::Message **message)
   826 	{
   827 		GETCHECK_FIELD();
   828 		CHECK_FIELD_TYPE(MESSAGE);
   829 		CHECK_FIELD_REPEATED();
   830 
   831 		*message = msg->GetReflection()->AddMessage(msg, field);
   832 
   833 		return true;
   834 	}
   835 
   836 	inline int GetRepeatedFieldCount(const char *pszFieldName)
   837 	{
   838 		const protobuf::FieldDescriptor *field = msg->GetDescriptor()->FindFieldByName(pszFieldName); \
   839 		if (!field)
   840 			return -1;
   841 
   842 		if (field->label() != protobuf::FieldDescriptor::LABEL_REPEATED)
   843 			return -1;
   844 
   845 		return msg->GetReflection()->FieldSize(*msg, field);
   846 	}
   847 
   848 private:
   849 	protobuf::Message *msg;
   850 	PBHandleList childHandles;
   851 };
   852 
   853 #endif // _INCLUDE_SOURCEMOD_SMPBMESSAGE_H_