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