extensions/sdktools/vdecoder.cpp
author Phong Dang <teame06@gmail.com>
Wed Aug 01 04:17:36 2007 +0000 (2007-08-01)
changeset 1235 88bb46f9731e
parent 1233 e9cfc03b9bb8
child 1330 ab94316bb52b
permissions -rw-r--r--
Implemented requested amb603. Added voice natives.
     1 /**
     2  * vim: set ts=4 :
     3  * ================================================================
     4  * SourceMod SDKTools Extension
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * ================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or 
     9  * modify it under the terms of the GNU General Public License, 
    10  * version 3.0, as published by the Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to 
    21  * link the code of this program (as well as its derivative works) to 
    22  * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
    23  * Game MODs that run on software by the Valve Corporation.  You must 
    24  * obey the GNU General Public License in all respects for all other 
    25  * code used. Additionally, AlliedModders LLC grants this exception 
    26  * to all derivative works. AlliedModders LLC defines further 
    27  * exceptions, found in LICENSE.txt (as of this writing, version 
    28  * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
    29  *
    30  * Version: $Id$
    31  */
    32 
    33 #include "smsdk_ext.h"
    34 #include "extension.h"
    35 #include "vdecoder.h"
    36 #include "vcallbuilder.h"
    37 
    38 using namespace SourceMod;
    39 using namespace SourcePawn;
    40 
    41 /**
    42  * For object pointers, the data looks like this instead:
    43  * 4 bytes: POINTER TO LATER
    44  * + bytes: Object internal data
    45  *
    46  * We use the virtual stack as extra fake stack space and create a temp object.
    47  * If these objects had destructors, we'd need to fake destroy toom of course.
    48  * Of course, BinTools only reads the first four bytes and passes the pointer.
    49  */
    50 
    51 size_t ValveParamToBinParam(ValveType type, 
    52 						  PassType pass,
    53 						  unsigned int flags,
    54 						  PassInfo *info,
    55 						  bool &needs_extra)
    56 {
    57 	needs_extra = false;
    58 	switch (type)
    59 	{
    60 	case Valve_Vector:
    61 		{
    62 			size_t mySize = sizeof(Vector *);
    63 			if (pass == PassType_Basic)
    64 			{
    65 				if (flags & PASSFLAG_BYREF)
    66 				{
    67 					return 0;
    68 				}
    69 				info->type = PassType_Basic;
    70 				info->flags = flags;
    71 				info->size = sizeof(Vector *);
    72 				mySize = sizeof(Vector);
    73 				needs_extra = true;
    74 			} else if (pass == PassType_Object) {
    75 				info->type = PassType_Object;
    76 				info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
    77 				info->size = sizeof(Vector);
    78 			} else {
    79 				return 0;
    80 			}
    81 			return mySize;
    82 		}
    83 	case Valve_QAngle:
    84 		{
    85 			size_t mySize = sizeof(QAngle *);
    86 			if (pass == PassType_Basic)
    87 			{
    88 				if (flags & PASSFLAG_BYREF)
    89 				{
    90 					return 0;
    91 				}
    92 				info->type = PassType_Basic;
    93 				info->flags = flags;
    94 				info->size = sizeof(QAngle *);
    95 				mySize = sizeof(QAngle);
    96 				needs_extra = true;
    97 			} else if (pass == PassType_Object) {
    98 				info->type = PassType_Object;
    99 				info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
   100 				info->size = sizeof(QAngle);
   101 			} else {
   102 				return 0;
   103 			}
   104 			return mySize;
   105 		}
   106 	case Valve_CBaseEntity:
   107 	case Valve_CBasePlayer:
   108 	case Valve_Edict:
   109 	case Valve_String:
   110 		{
   111 			if (pass != PassType_Basic || (flags & PASSFLAG_BYREF))
   112 			{
   113 				return 0;
   114 			}
   115 			info->type = PassType_Basic;
   116 			info->flags = flags;
   117 			info->size = sizeof(void *);
   118 			return sizeof(void *);
   119 		}
   120 	case Valve_POD:
   121 		{
   122 			info->type = PassType_Basic;
   123 			info->flags = flags;
   124 			if (flags & PASSFLAG_ASPOINTER)
   125 			{
   126 				needs_extra = true;
   127 				info->size = sizeof(int *);
   128 				return sizeof(int *) + sizeof(int);
   129 			} else {
   130 				info->size = sizeof(int);
   131 				return sizeof(int);
   132 			}
   133 		}
   134 	case Valve_Bool:
   135 		{
   136 			info->type = PassType_Basic;
   137 			info->flags = flags;
   138 			if (flags & PASSFLAG_ASPOINTER)
   139 			{
   140 				needs_extra = true;
   141 				info->size = sizeof(bool *);
   142 				return sizeof(bool *) + sizeof(bool);
   143 			} else {
   144 				info->size = sizeof(bool);
   145 				return sizeof(bool);
   146 			}
   147 		}
   148 	case Valve_Float:
   149 		{
   150 			info->flags = flags;
   151 			if (flags & PASSFLAG_ASPOINTER)
   152 			{
   153 				needs_extra = true;
   154 				info->type = PassType_Basic;
   155 				info->size = sizeof(float *);
   156 				return sizeof(float *) + sizeof(float);
   157 			} else {
   158 				info->type = PassType_Float;
   159 				info->size = sizeof(float);
   160 				return sizeof(float);
   161 			}
   162 		}
   163 	}
   164 
   165 	return 0;
   166 }
   167 
   168 DataStatus EncodeValveParam(IPluginContext *pContext,
   169 							cell_t param, 
   170 							const ValveCall *pCall,
   171 							const ValvePassInfo *data,
   172 							const void *_buffer)
   173 {
   174 	const void *buffer = (const unsigned char *)_buffer + data->offset;
   175 	switch (data->vtype)
   176 	{
   177 	case Valve_Vector:
   178 		{
   179 			Vector *v = NULL;
   180 
   181 			if (data->type == PassType_Basic)
   182 			{
   183 				v = *(Vector **)buffer;
   184 			} else if (data->type == PassType_Object) {
   185 				v = (Vector *)buffer;
   186 			}
   187 
   188 			cell_t *addr;
   189 			pContext->LocalToPhysAddr(param, &addr);
   190 
   191 			addr[0] = sp_ftoc(v->x);
   192 			addr[1] = sp_ftoc(v->y);
   193 			addr[2] = sp_ftoc(v->z);
   194 
   195 			return Data_Okay;
   196 		}
   197 	case Valve_QAngle:
   198 		{
   199 			QAngle *q = NULL;
   200 
   201 			if (data->type == PassType_Basic)
   202 			{
   203 				q = *(QAngle **)buffer;
   204 			} else if (data->type == PassType_Object) {
   205 				q = (QAngle *)buffer;
   206 			}
   207 
   208 			cell_t *addr;
   209 			pContext->LocalToPhysAddr(param, &addr);
   210 
   211 			addr[0] = sp_ftoc(q->x);
   212 			addr[1] = sp_ftoc(q->y);
   213 			addr[2] = sp_ftoc(q->z);
   214 
   215 			return Data_Okay;
   216 		}
   217 	case Valve_CBaseEntity:
   218 	case Valve_CBasePlayer:
   219 		{
   220 			cell_t *addr;
   221 			pContext->LocalToPhysAddr(param, &addr);
   222 
   223 			CBaseEntity *pEntity = *(CBaseEntity **)buffer;
   224 			if (pEntity)
   225 			{
   226 				edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
   227 				*addr = engine->IndexOfEdict(pEdict);
   228 			} else {
   229 				*addr = -1;
   230 			}
   231 
   232 			return Data_Okay;
   233 		}
   234 	case Valve_Edict:
   235 		{
   236 			cell_t *addr;
   237 			pContext->LocalToPhysAddr(param, &addr);
   238 
   239 			edict_t *pEdict = *(edict_t **)buffer;
   240 			if (pEdict)
   241 			{
   242 				*addr = engine->IndexOfEdict(pEdict);
   243 			} else {
   244 				*addr = -1;
   245 			}
   246 
   247 			return Data_Okay;
   248 		}
   249 	case Valve_POD:
   250 	case Valve_Float:
   251 		{
   252 			cell_t *addr;
   253 			pContext->LocalToPhysAddr(param, &addr);
   254 
   255 			if (data->flags & PASSFLAG_ASPOINTER)
   256 			{
   257 				buffer = *(cell_t **)buffer;
   258 			}
   259 
   260 			*addr = *(cell_t *)buffer;
   261 
   262 			return Data_Okay;
   263 		}
   264 	case Valve_Bool:
   265 		{
   266 			cell_t *addr;
   267 			pContext->LocalToPhysAddr(param, &addr);
   268 
   269 			if (data->flags & PASSFLAG_ASPOINTER)
   270 			{
   271 				buffer = *(bool **)buffer;
   272 			}
   273 
   274 			*addr = *(bool *)buffer ? 1 : 0;
   275 
   276 			return Data_Okay;
   277 		}
   278 	}
   279 
   280 	return Data_Fail;
   281 }
   282 
   283 DataStatus DecodeValveParam(IPluginContext *pContext,
   284 					  cell_t param,
   285 					  const ValveCall *pCall,
   286 					  const ValvePassInfo *data,
   287 					  void *_buffer)
   288 {
   289 	void *buffer = (unsigned char *)_buffer + data->offset;
   290 	switch (data->vtype)
   291 	{
   292 	case Valve_Vector:
   293 		{
   294 			cell_t *addr;
   295 			int err;
   296 			err = pContext->LocalToPhysAddr(param, &addr);
   297 
   298 			unsigned char *mem = (unsigned char *)buffer;
   299 			if (data->type == PassType_Basic)
   300 			{
   301 				/* Store the object in the next N bytes, and store
   302 				 * a pointer to that object right beforehand.
   303 				 */
   304 				Vector **realPtr = (Vector **)buffer;
   305 
   306 				if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
   307 				{
   308 					if (data->decflags & VDECODE_FLAG_ALLOWNULL)
   309 					{
   310 						*realPtr = NULL;
   311 						return Data_Okay;
   312 					} else {
   313 						pContext->ThrowNativeError("NULL not allowed");
   314 						return Data_Fail;
   315 					}
   316 				} else {
   317 					mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
   318 					*realPtr = (Vector *)mem;
   319 				}
   320 			}
   321 
   322 			if (err != SP_ERROR_NONE)
   323 			{
   324 				pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
   325 				return Data_Fail;
   326 			}
   327 
   328 			/* Use placement new to initialize the object cleanly
   329 			 * This has no destructor so we don't need to do 
   330 			 * DestroyValveParam() or something :]
   331 			 */
   332 			Vector *v = new (mem) Vector(
   333 				sp_ctof(addr[0]),
   334 				sp_ctof(addr[1]),
   335 				sp_ctof(addr[2]));
   336 
   337 			return Data_Okay;
   338 		}
   339 	case Valve_QAngle:
   340 		{
   341 			cell_t *addr;
   342 			int err;
   343 			err = pContext->LocalToPhysAddr(param, &addr);
   344 
   345 			unsigned char *mem = (unsigned char *)buffer;
   346 			if (data->type == PassType_Basic)
   347 			{
   348 				/* Store the object in the next N bytes, and store
   349 				 * a pointer to that object right beforehand.
   350 				 */
   351 				QAngle **realPtr = (QAngle **)buffer;
   352 
   353 				if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
   354 				{
   355 					if (!(data->decflags & VDECODE_FLAG_ALLOWNULL))
   356 					{
   357 						pContext->ThrowNativeError("NULL not allowed");
   358 						return Data_Fail;
   359 					} else {
   360 						*realPtr = NULL;
   361 						return Data_Okay;
   362 					}
   363 				} else {
   364 					mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
   365 					*realPtr = (QAngle *)mem;
   366 				}
   367 			}
   368 
   369 			if (err != SP_ERROR_NONE)
   370 			{
   371 				pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
   372 				return Data_Fail;
   373 			}
   374 
   375 			/* Use placement new to initialize the object cleanly
   376 			 * This has no destructor so we don't need to do 
   377 			 * DestroyValveParam() or something :]
   378 			 */
   379 			QAngle *v = new (mem) QAngle(
   380 				sp_ctof(addr[0]),
   381 				sp_ctof(addr[1]),
   382 				sp_ctof(addr[2]));
   383 
   384 			return Data_Okay;
   385 		}
   386 	case Valve_CBasePlayer:
   387 		{
   388 			edict_t *pEdict;
   389 			if (data->decflags & VDECODE_FLAG_BYREF)
   390 			{
   391 				cell_t *addr;
   392 				pContext->LocalToPhysAddr(param, &addr);
   393 				param = *addr;
   394 			}
   395 			if (param >= 1 && param <= playerhelpers->GetMaxClients())
   396 			{
   397 				IGamePlayer *player = playerhelpers->GetGamePlayer(param);
   398 				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
   399 					&& !player->IsConnected())
   400 				{
   401 					pContext->ThrowNativeError("Client %d is not connected", param);
   402 					return Data_Fail;
   403 				} else if (!player->IsInGame()) {
   404 					pContext->ThrowNativeError("Client %d is not in game", param);
   405 					return Data_Fail;
   406 				}
   407 				pEdict = player->GetEdict();
   408 			} else if (param == -1) {
   409 				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
   410 				{
   411 					pEdict = NULL;
   412 				} else {
   413 					pContext->ThrowNativeError("NULL not allowed");
   414 					return Data_Fail;
   415 				}
   416 			} else if (param == 0) {
   417 				if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
   418 				{
   419 					pEdict = engine->PEntityOfEntIndex(0);
   420 				} else {
   421 					pContext->ThrowNativeError("World not allowed");
   422 					return Data_Fail;
   423 				}
   424 			} else {
   425 				pContext->ThrowNativeError("Entity index %d is not a valid client", param);
   426 				return Data_Fail;
   427 			}
   428 			CBaseEntity *pEntity = NULL;
   429 			if (pEdict)
   430 			{
   431 				IServerUnknown *pUnknown = pEdict->GetUnknown();
   432 				if (!pUnknown)
   433 				{
   434 					pContext->ThrowNativeError("Entity %d is a not an IServerUnknown");
   435 					return Data_Fail;
   436 				}
   437 				pEntity = pUnknown->GetBaseEntity();
   438 				if (!pEntity)
   439 				{
   440 					pContext->ThrowNativeError("Entity %d is not a CBaseEntity");
   441 					return Data_Fail;
   442 				}
   443 			}
   444 
   445 			CBaseEntity **ebuf = (CBaseEntity **)buffer;
   446 			*ebuf = pEntity;
   447 
   448 			return Data_Okay;
   449 		}
   450 	case Valve_CBaseEntity:
   451 		{
   452 			edict_t *pEdict;
   453 			if (data->decflags & VDECODE_FLAG_BYREF)
   454 			{
   455 				cell_t *addr;
   456 				pContext->LocalToPhysAddr(param, &addr);
   457 				param = *addr;
   458 			}
   459 			if (param >= 1 && param <= playerhelpers->GetMaxClients())
   460 			{
   461 				IGamePlayer *player = playerhelpers->GetGamePlayer(param);
   462 				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
   463 					&& !player->IsConnected())
   464 				{
   465 					pContext->ThrowNativeError("Client %d is not connected", param);
   466 					return Data_Fail;
   467 				} else if (!player->IsInGame()) {
   468 					pContext->ThrowNativeError("Client %d is not in game", param);
   469 					return Data_Fail;
   470 				}
   471 				pEdict = player->GetEdict();
   472 			} else if (param == -1) {
   473 				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
   474 				{
   475 					pEdict = NULL;
   476 				} else {
   477 					pContext->ThrowNativeError("NULL not allowed");
   478 					return Data_Fail;
   479 				}
   480 			} else if (param == 0) {
   481 				if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
   482 				{
   483 					pEdict = engine->PEntityOfEntIndex(0);
   484 				} else {
   485 					pContext->ThrowNativeError("World not allowed");
   486 					return Data_Fail;
   487 				}
   488 			} else {
   489 				pEdict = engine->PEntityOfEntIndex(param);
   490 				if (!pEdict || pEdict->IsFree())
   491 				{
   492 					pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
   493 					return Data_Fail;
   494 				}
   495 			}
   496 			CBaseEntity *pEntity = NULL;
   497 			if (pEdict)
   498 			{
   499 				IServerUnknown *pUnknown = pEdict->GetUnknown();
   500 				if (!pUnknown)
   501 				{
   502 					pContext->ThrowNativeError("Entity %d is a not an IServerUnknown");
   503 					return Data_Fail;
   504 				}
   505 				pEntity = pUnknown->GetBaseEntity();
   506 				if (!pEntity)
   507 				{
   508 					pContext->ThrowNativeError("Entity %d is not a CBaseEntity");
   509 					return Data_Fail;
   510 				}
   511 			}
   512 
   513 			CBaseEntity **ebuf = (CBaseEntity **)buffer;
   514 			*ebuf = pEntity;
   515 
   516 			return Data_Okay;
   517 		}
   518 	case Valve_Edict:
   519 		{
   520 			edict_t *pEdict;
   521 			if (data->decflags & VDECODE_FLAG_BYREF)
   522 			{
   523 				cell_t *addr;
   524 				pContext->LocalToPhysAddr(param, &addr);
   525 				param = *addr;
   526 			}
   527 			if (param >= 1 && param <= playerhelpers->GetMaxClients())
   528 			{
   529 				IGamePlayer *player = playerhelpers->GetGamePlayer(param);
   530 				if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
   531 					&& !player->IsConnected())
   532 				{
   533 					pContext->ThrowNativeError("Client %d is not connected", param);
   534 					return Data_Fail;
   535 				} else if (!player->IsInGame()) {
   536 					pContext->ThrowNativeError("Client %d is not in game", param);
   537 					return Data_Fail;
   538 				}
   539 				pEdict = player->GetEdict();
   540 			} else if (param == -1) {
   541 				if (data->decflags & VDECODE_FLAG_ALLOWNULL)
   542 				{
   543 					pEdict = NULL;
   544 				} else {
   545 					pContext->ThrowNativeError("NULL not allowed");
   546 					return Data_Fail;
   547 				}
   548 			} else if (param == 0) {
   549 				if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
   550 				{
   551 					pEdict = engine->PEntityOfEntIndex(0);
   552 				} else {
   553 					pContext->ThrowNativeError("World not allowed");
   554 					return Data_Fail;
   555 				}
   556 			} else {
   557 				pEdict = engine->PEntityOfEntIndex(param);
   558 				if (!pEdict || pEdict->IsFree())
   559 				{
   560 					pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
   561 					return Data_Fail;
   562 				}
   563 			}
   564 
   565 			edict_t **ebuf = (edict_t **)buffer;
   566 			*ebuf = pEdict;
   567 
   568 			return Data_Okay;
   569 		}
   570 	case Valve_POD:
   571 	case Valve_Float:
   572 		{
   573 			if (data->decflags & VDECODE_FLAG_BYREF)
   574 			{
   575 				cell_t *addr;
   576 				pContext->LocalToPhysAddr(param, &addr);
   577 				param = *addr;
   578 			}
   579 			if (data->flags & PASSFLAG_ASPOINTER)
   580 			{
   581 				*(void **)buffer = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
   582 				buffer = *(void **)buffer;
   583 			}
   584 			*(cell_t *)buffer = param;
   585 			return Data_Okay;
   586 		}
   587 	case Valve_Bool:
   588 		{
   589 			if (data->decflags & VDECODE_FLAG_BYREF)
   590 			{
   591 				cell_t *addr;
   592 				pContext->LocalToPhysAddr(param, &addr);
   593 				param = *addr;
   594 			}
   595 			if (data->flags & PASSFLAG_ASPOINTER)
   596 			{
   597 				*(bool **)buffer = (bool *)((unsigned char *)_buffer + pCall->stackEnd + data->obj_offset);
   598 				buffer = *(bool **)buffer;
   599 			}
   600 			*(bool *)buffer = param ? true : false;
   601 			return Data_Okay;
   602 		}
   603 	case Valve_String:
   604 		{
   605 			char *addr;
   606 			pContext->LocalToString(param, &addr);
   607 			*(char **)buffer = addr;
   608 			return Data_Okay;
   609 		}
   610 	}
   611 
   612 	return Data_Fail;
   613 }