extensions/sdktools/vdecoder.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 2750 703c1e857130
permissions -rw-r--r--
Update CS:GO team score gamedata.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod SDKTools Extension
     5  * Copyright (C) 2004-2008 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 #include "smsdk_ext.h"
    33 #include "extension.h"
    34 #include "vdecoder.h"
    35 #include "vcallbuilder.h"
    36 
    37 using namespace SourceMod;
    38 using namespace SourcePawn;
    39 
    40 /**
    41  * For object pointers, the data looks like this instead:
    42  * 4 bytes: POINTER TO LATER
    43  * + bytes: Object internal data
    44  *
    45  * We use the virtual stack as extra fake stack space and create a temp object.
    46  * If these objects had destructors, we'd need to fake destroy toom of course.
    47  * Of course, BinTools only reads the first four bytes and passes the pointer.
    48  */
    49 
    50 size_t ValveParamToBinParam(ValveType type, 
    51 						  PassType pass,
    52 						  unsigned int flags,
    53 						  PassInfo *info,
    54 						  bool &needs_extra)
    55 {
    56 	needs_extra = false;
    57 	switch (type)
    58 	{
    59 	case Valve_Vector:
    60 		{
    61 			size_t mySize = sizeof(Vector *);
    62 			if (pass == PassType_Basic)
    63 			{
    64 				if (flags & PASSFLAG_BYREF)
    65 				{
    66 					return 0;
    67 				}
    68 				info->type = PassType_Basic;
    69 				info->flags = flags;
    70 				info->size = sizeof(Vector *);
    71 				mySize = sizeof(Vector);
    72 				needs_extra = true;
    73 			} else if (pass == PassType_Object) {
    74 				info->type = PassType_Object;
    75 				info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
    76 				info->size = sizeof(Vector);
    77 			} else {
    78 				return 0;
    79 			}
    80 			return mySize;
    81 		}
    82 	case Valve_QAngle:
    83 		{
    84 			size_t mySize = sizeof(QAngle *);
    85 			if (pass == PassType_Basic)
    86 			{
    87 				if (flags & PASSFLAG_BYREF)
    88 				{
    89 					return 0;
    90 				}
    91 				info->type = PassType_Basic;
    92 				info->flags = flags;
    93 				info->size = sizeof(QAngle *);
    94 				mySize = sizeof(QAngle);
    95 				needs_extra = true;
    96 			} else if (pass == PassType_Object) {
    97 				info->type = PassType_Object;
    98 				info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
    99 				info->size = sizeof(QAngle);
   100 			} else {
   101 				return 0;
   102 			}
   103 			return mySize;
   104 		}
   105 	case Valve_CBaseEntity:
   106 	case Valve_CBasePlayer:
   107 	case Valve_Edict:
   108 	case Valve_String:
   109 		{
   110 			if (pass != PassType_Basic || (flags & PASSFLAG_BYREF))
   111 			{
   112 				return 0;
   113 			}
   114 			info->type = PassType_Basic;
   115 			info->flags = flags;
   116 			info->size = sizeof(void *);
   117 			return sizeof(void *);
   118 		}
   119 	case Valve_POD:
   120 		{
   121 			info->type = PassType_Basic;
   122 			info->flags = flags;
   123 			if (flags & PASSFLAG_ASPOINTER)
   124 			{
   125 				needs_extra = true;
   126 				info->size = sizeof(int *);
   127 				return sizeof(int *) + sizeof(int);
   128 			} else {
   129 				info->size = sizeof(int);
   130 				return sizeof(int);
   131 			}
   132 		}
   133 	case Valve_Bool:
   134 		{
   135 			info->type = PassType_Basic;
   136 			info->flags = flags;
   137 			if (flags & PASSFLAG_ASPOINTER)
   138 			{
   139 				needs_extra = true;
   140 				info->size = sizeof(bool *);
   141 				return sizeof(bool *) + sizeof(bool);
   142 			} else {
   143 				info->size = sizeof(bool);
   144 				return sizeof(bool);
   145 			}
   146 		}
   147 	case Valve_Float:
   148 		{
   149 			info->flags = flags;
   150 			if (flags & PASSFLAG_ASPOINTER)
   151 			{
   152 				needs_extra = true;
   153 				info->type = PassType_Basic;
   154 				info->size = sizeof(float *);
   155 				return sizeof(float *) + sizeof(float);
   156 			} else {
   157 				info->type = PassType_Float;
   158 				info->size = sizeof(float);
   159 				return sizeof(float);
   160 			}
   161 		}
   162 	}
   163 
   164 	return 0;
   165 }
   166 
   167 DataStatus EncodeValveParam(IPluginContext *pContext,
   168 							cell_t param, 
   169 							const ValveCall *pCall,
   170 							const ValvePassInfo *data,
   171 							const void *_buffer)
   172 {
   173 	const void *buffer = (const unsigned char *)_buffer + data->offset;
   174 	switch (data->vtype)
   175 	{
   176 	case Valve_Vector:
   177 		{
   178 			Vector *v = NULL;
   179 
   180 			if (data->type == PassType_Basic)
   181 			{
   182 				v = *(Vector **)buffer;
   183 			} else if (data->type == PassType_Object) {
   184 				v = (Vector *)buffer;
   185 			}
   186 
   187 			cell_t *addr;
   188 			pContext->LocalToPhysAddr(param, &addr);
   189 
   190 			addr[0] = sp_ftoc(v->x);
   191 			addr[1] = sp_ftoc(v->y);
   192 			addr[2] = sp_ftoc(v->z);
   193 
   194 			return Data_Okay;
   195 		}
   196 	case Valve_QAngle:
   197 		{
   198 			QAngle *q = NULL;
   199 
   200 			if (data->type == PassType_Basic)
   201 			{
   202 				q = *(QAngle **)buffer;
   203 			} else if (data->type == PassType_Object) {
   204 				q = (QAngle *)buffer;
   205 			}
   206 
   207 			cell_t *addr;
   208 			pContext->LocalToPhysAddr(param, &addr);
   209 
   210 			addr[0] = sp_ftoc(q->x);
   211 			addr[1] = sp_ftoc(q->y);
   212 			addr[2] = sp_ftoc(q->z);
   213 
   214 			return Data_Okay;
   215 		}
   216 	case Valve_CBaseEntity:
   217 	case Valve_CBasePlayer:
   218 		{
   219 			cell_t *addr;
   220 			pContext->LocalToPhysAddr(param, &addr);
   221 
   222 			CBaseEntity *pEntity = *(CBaseEntity **)buffer;
   223 			if (pEntity)
   224 			{
   225 				*addr = gamehelpers->EntityToBCompatRef(pEntity);
   226 			} else {
   227 				*addr = -1;
   228 			}
   229 
   230 			return Data_Okay;
   231 		}
   232 	case Valve_Edict:
   233 		{
   234 			cell_t *addr;
   235 			pContext->LocalToPhysAddr(param, &addr);
   236 
   237 			edict_t *pEdict = *(edict_t **)buffer;
   238 			if (pEdict)
   239 			{
   240 				*addr = IndexOfEdict(pEdict);
   241 			} else {
   242 				*addr = -1;
   243 			}
   244 
   245 			return Data_Okay;
   246 		}
   247 	case Valve_POD:
   248 	case Valve_Float:
   249 		{
   250 			cell_t *addr;
   251 			pContext->LocalToPhysAddr(param, &addr);
   252 
   253 			if (data->flags & PASSFLAG_ASPOINTER)
   254 			{
   255 				buffer = *(cell_t **)buffer;
   256 			}
   257 
   258 			*addr = *(cell_t *)buffer;
   259 
   260 			return Data_Okay;
   261 		}
   262 	case Valve_Bool:
   263 		{
   264 			cell_t *addr;
   265 			pContext->LocalToPhysAddr(param, &addr);
   266 
   267 			if (data->flags & PASSFLAG_ASPOINTER)
   268 			{
   269 				buffer = *(bool **)buffer;
   270 			}
   271 
   272 			*addr = *(bool *)buffer ? 1 : 0;
   273 
   274 			return Data_Okay;
   275 		}
   276 	}
   277 
   278 	return Data_Fail;
   279 }
   280 
   281 DataStatus DecodeValveParam(IPluginContext *pContext,
   282 					  cell_t param,
   283 					  const ValveCall *pCall,
   284 					  const ValvePassInfo *data,
   285 					  void *_buffer)
   286 {
   287 	void *buffer = (unsigned char *)_buffer + data->offset;
   288 	switch (data->vtype)
   289 	{
   290 	case Valve_Vector:
   291 		{
   292 			cell_t *addr;
   293 			int err;
   294 			err = pContext->LocalToPhysAddr(param, &addr);
   295 
   296 			unsigned char *mem = (unsigned char *)buffer;
   297 			if (data->type == PassType_Basic)
   298 			{
   299 				/* Store the object in the next N bytes, and store
   300 				 * a pointer to that object right beforehand.
   301 				 */
   302 				Vector **realPtr = (Vector **)buffer;
   303 
   304 				if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
   305 				{
   306 					if (data->decflags & VDECODE_FLAG_ALLOWNULL)
   307 					{
   308 						*realPtr = NULL;
   309 						return Data_Okay;
   310 					} else {
   311 						pContext->ThrowNativeError("NULL not allowed");
   312 						return Data_Fail;
   313 					}
   314 				} else {
   315 					mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
   316 					*realPtr = (Vector *)mem;
   317 				}
   318 			}
   319 
   320 			if (err != SP_ERROR_NONE)
   321 			{
   322 				pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
   323 				return Data_Fail;
   324 			}
   325 
   326 			/* Use placement new to initialize the object cleanly
   327 			 * This has no destructor so we don't need to do 
   328 			 * DestroyValveParam() or something :]
   329 			 */
   330 			Vector *v = new (mem) Vector(
   331 				sp_ctof(addr[0]),
   332 				sp_ctof(addr[1]),
   333 				sp_ctof(addr[2]));
   334 
   335 			return Data_Okay;
   336 		}
   337 	case Valve_QAngle:
   338 		{
   339 			cell_t *addr;
   340 			int err;
   341 			err = pContext->LocalToPhysAddr(param, &addr);
   342 
   343 			unsigned char *mem = (unsigned char *)buffer;
   344 			if (data->type == PassType_Basic)
   345 			{
   346 				/* Store the object in the next N bytes, and store
   347 				 * a pointer to that object right beforehand.
   348 				 */
   349 				QAngle **realPtr = (QAngle **)buffer;
   350 
   351 				if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
   352 				{
   353 					if (!(data->decflags & VDECODE_FLAG_ALLOWNULL))
   354 					{
   355 						pContext->ThrowNativeError("NULL not allowed");
   356 						return Data_Fail;
   357 					} else {
   358 						*realPtr = NULL;
   359 						return Data_Okay;
   360 					}
   361 				} else {
   362 					mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
   363 					*realPtr = (QAngle *)mem;
   364 				}
   365 			}
   366 
   367 			if (err != SP_ERROR_NONE)
   368 			{
   369 				pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
   370 				return Data_Fail;
   371 			}
   372 
   373 			/* Use placement new to initialize the object cleanly
   374 			 * This has no destructor so we don't need to do 
   375 			 * DestroyValveParam() or something :]
   376 			 */
   377 			QAngle *v = new (mem) QAngle(
   378 				sp_ctof(addr[0]),
   379 				sp_ctof(addr[1]),
   380 				sp_ctof(addr[2]));
   381 
   382 			return Data_Okay;
   383 		}
   384 	case Valve_CBasePlayer:
   385 		{
   386 			CBaseEntity *pEntity = NULL;
   387 			if (data->decflags & VDECODE_FLAG_BYREF)
   388 			{
   389 				cell_t *addr;
   390 				pContext->LocalToPhysAddr(param, &addr);
   391 				param = *addr;
   392 			}
   393 			int index = gamehelpers->ReferenceToIndex(param);
   394 			if ((unsigned)index == INVALID_EHANDLE_INDEX && param != -1)
   395 			{
   396 				return Data_Fail;
   397 			}
   398 			if (index >= 1 && index <= playerhelpers->GetMaxClients())
   399 			{
   400 				IGamePlayer *player = playerhelpers->GetGamePlayer(index);
   401 				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
   402 					&& !player->IsConnected())
   403 				{
   404 					pContext->ThrowNativeError("Client %d is not connected", param);
   405 					return Data_Fail;
   406 				} else if (!player->IsInGame()) {
   407 					pContext->ThrowNativeError("Client %d is not in game", param);
   408 					return Data_Fail;
   409 				}
   410 				pEntity = gamehelpers->ReferenceToEntity(param);
   411 			} else if (param == -1) {
   412 				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
   413 				{
   414 					pEntity = NULL;
   415 				} else {
   416 					pContext->ThrowNativeError("NULL not allowed");
   417 					return Data_Fail;
   418 				}
   419 			} else {
   420 				pContext->ThrowNativeError("Entity index %d is not a valid client", param);
   421 				return Data_Fail;
   422 			}
   423 			
   424 			CBaseEntity **ebuf = (CBaseEntity **)buffer;
   425 			*ebuf = pEntity;
   426 
   427 			return Data_Okay;
   428 		}
   429 	case Valve_CBaseEntity:
   430 		{
   431 			CBaseEntity *pEntity = NULL;
   432 			if (data->decflags & VDECODE_FLAG_BYREF)
   433 			{
   434 				cell_t *addr;
   435 				pContext->LocalToPhysAddr(param, &addr);
   436 				param = *addr;
   437 			}
   438 			int index = gamehelpers->ReferenceToIndex(param);
   439 			if ((unsigned)index == INVALID_EHANDLE_INDEX && param != -1)
   440 			{
   441 				return Data_Fail;
   442 			}
   443 			if (index >= 1 && index <= playerhelpers->GetMaxClients())
   444 			{
   445 				IGamePlayer *player = playerhelpers->GetGamePlayer(index);
   446 				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
   447 					&& !player->IsConnected())
   448 				{
   449 					pContext->ThrowNativeError("Client %d is not connected", param);
   450 					return Data_Fail;
   451 				} else if (!player->IsInGame()) {
   452 					pContext->ThrowNativeError("Client %d is not in game", param);
   453 					return Data_Fail;
   454 				}
   455 				pEntity = gamehelpers->ReferenceToEntity(param);
   456 			} else if (param == -1) {
   457 				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
   458 				{
   459 					pEntity = NULL;
   460 				} else {
   461 					pContext->ThrowNativeError("NULL not allowed");
   462 					return Data_Fail;
   463 				}
   464 			} else if (index == 0) {
   465 				if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
   466 				{
   467 					pEntity = gamehelpers->ReferenceToEntity(0);
   468 				} else {
   469 					pContext->ThrowNativeError("World not allowed");
   470 					return Data_Fail;
   471 				}
   472 			} else {
   473 				pEntity = gamehelpers->ReferenceToEntity(param);
   474 				if (!pEntity)
   475 				{
   476 					pContext->ThrowNativeError("Entity %d is not valid", param);
   477 					return Data_Fail;
   478 				}
   479 			}
   480 
   481 			CBaseEntity **ebuf = (CBaseEntity **)buffer;
   482 			*ebuf = pEntity;
   483 
   484 			return Data_Okay;
   485 		}
   486 	case Valve_Edict:
   487 		{
   488 			edict_t *pEdict;
   489 			if (data->decflags & VDECODE_FLAG_BYREF)
   490 			{
   491 				cell_t *addr;
   492 				pContext->LocalToPhysAddr(param, &addr);
   493 				param = *addr;
   494 			}
   495 			if (param >= 1 && param <= playerhelpers->GetMaxClients())
   496 			{
   497 				IGamePlayer *player = playerhelpers->GetGamePlayer(param);
   498 				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
   499 					&& !player->IsConnected())
   500 				{
   501 					pContext->ThrowNativeError("Client %d is not connected", param);
   502 					return Data_Fail;
   503 				} else if (!player->IsInGame()) {
   504 					pContext->ThrowNativeError("Client %d is not in game", param);
   505 					return Data_Fail;
   506 				}
   507 				pEdict = player->GetEdict();
   508 			} else if (param == -1) {
   509 				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
   510 				{
   511 					pEdict = NULL;
   512 				} else {
   513 					pContext->ThrowNativeError("NULL not allowed");
   514 					return Data_Fail;
   515 				}
   516 			} else if (param == 0) {
   517 				if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
   518 				{
   519 					pEdict = PEntityOfEntIndex(0);
   520 				} else {
   521 					pContext->ThrowNativeError("World not allowed");
   522 					return Data_Fail;
   523 				}
   524 			} else {
   525 				pEdict = PEntityOfEntIndex(param);
   526 				if (!pEdict || pEdict->IsFree())
   527 				{
   528 					pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
   529 					return Data_Fail;
   530 				}
   531 			}
   532 
   533 			edict_t **ebuf = (edict_t **)buffer;
   534 			*ebuf = pEdict;
   535 
   536 			return Data_Okay;
   537 		}
   538 	case Valve_POD:
   539 	case Valve_Float:
   540 		{
   541 			if (data->decflags & VDECODE_FLAG_BYREF)
   542 			{
   543 				cell_t *addr;
   544 				pContext->LocalToPhysAddr(param, &addr);
   545 				param = *addr;
   546 			}
   547 			if (data->flags & PASSFLAG_ASPOINTER)
   548 			{
   549 				*(void **)buffer = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
   550 				buffer = *(void **)buffer;
   551 			}
   552 			*(cell_t *)buffer = param;
   553 			return Data_Okay;
   554 		}
   555 	case Valve_Bool:
   556 		{
   557 			if (data->decflags & VDECODE_FLAG_BYREF)
   558 			{
   559 				cell_t *addr;
   560 				pContext->LocalToPhysAddr(param, &addr);
   561 				param = *addr;
   562 			}
   563 			if (data->flags & PASSFLAG_ASPOINTER)
   564 			{
   565 				*(bool **)buffer = (bool *)((unsigned char *)_buffer + pCall->stackEnd + data->obj_offset);
   566 				buffer = *(bool **)buffer;
   567 			}
   568 			*(bool *)buffer = param ? true : false;
   569 			return Data_Okay;
   570 		}
   571 	case Valve_String:
   572 		{
   573 			char *addr;
   574 			pContext->LocalToString(param, &addr);
   575 			*(char **)buffer = addr;
   576 			return Data_Okay;
   577 		}
   578 	}
   579 
   580 	return Data_Fail;
   581 }