1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/extensions/sdktools/vdecoder.cpp Sat Jun 16 08:36:34 2007 +0000
1.3 @@ -0,0 +1,505 @@
1.4 +#include "smsdk_ext.h"
1.5 +#include "extension.h"
1.6 +#include "vdecoder.h"
1.7 +
1.8 +using namespace SourceMod;
1.9 +using namespace SourcePawn;
1.10 +
1.11 +/**
1.12 + * For object pointers, the data looks like this instead:
1.13 + * 4 bytes: POINTER TO NEXT FOUR BYTES
1.14 + * + bytes: Object internal data
1.15 + *
1.16 + * We use the virtual stack as extra fake stack space and create a temp object.
1.17 + * If these objects had destructors, we'd need to fake destroy toom of course.
1.18 + * Of course, BinTools only reads the first four bytes and passes the pointer.
1.19 + */
1.20 +
1.21 +size_t ValveParamToBinParam(ValveType type,
1.22 + PassType pass,
1.23 + unsigned int flags,
1.24 + PassInfo *info)
1.25 +{
1.26 + switch (type)
1.27 + {
1.28 + case Valve_Vector:
1.29 + {
1.30 + size_t mySize = sizeof(Vector *);
1.31 + if (pass == PassType_Basic)
1.32 + {
1.33 + if (info->flags & PASSFLAG_BYREF)
1.34 + {
1.35 + return 0;
1.36 + }
1.37 + info->type = PassType_Basic;
1.38 + info->flags = flags;
1.39 + info->size = sizeof(Vector *);
1.40 + mySize += sizeof(Vector);
1.41 + } else if (pass == PassType_Object) {
1.42 + info->type = PassType_Object;
1.43 + info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
1.44 + info->size = sizeof(Vector);
1.45 + } else {
1.46 + return 0;
1.47 + }
1.48 + return mySize;
1.49 + }
1.50 + case Valve_QAngle:
1.51 + {
1.52 + size_t mySize = sizeof(QAngle *);
1.53 + if (pass == PassType_Basic)
1.54 + {
1.55 + if (info->flags & PASSFLAG_BYREF)
1.56 + {
1.57 + return 0;
1.58 + }
1.59 + info->type = PassType_Basic;
1.60 + info->flags = flags;
1.61 + info->size = sizeof(QAngle *);
1.62 + mySize += sizeof(QAngle);
1.63 + } else if (pass == PassType_Object) {
1.64 + info->type = PassType_Object;
1.65 + info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
1.66 + info->size = sizeof(QAngle);
1.67 + } else {
1.68 + return 0;
1.69 + }
1.70 + return mySize;
1.71 + }
1.72 + case Valve_CBaseEntity:
1.73 + case Valve_CBasePlayer:
1.74 + case Valve_POD:
1.75 + case Valve_Edict:
1.76 + case Valve_String:
1.77 + {
1.78 + if (pass != PassType_Basic
1.79 + || (info->flags & PASSFLAG_BYREF))
1.80 + {
1.81 + return 0;
1.82 + }
1.83 + info->type = PassType_Basic;
1.84 + info->flags = flags;
1.85 + info->size = sizeof(void *);
1.86 + return sizeof(void *);
1.87 + }
1.88 + case Valve_Float:
1.89 + {
1.90 + info->type = PassType_Float;
1.91 + info->flags = flags;
1.92 + info->size = sizeof(float);
1.93 + return sizeof(float);
1.94 + }
1.95 + }
1.96 +
1.97 + return 0;
1.98 +}
1.99 +
1.100 +DataStatus EncodeValveParam(IPluginContext *pContext,
1.101 + cell_t param,
1.102 + ValveType type,
1.103 + PassType pass,
1.104 + const void *buffer)
1.105 +{
1.106 + switch (type)
1.107 + {
1.108 + case Valve_Vector:
1.109 + {
1.110 + Vector *v = NULL;
1.111 +
1.112 + if (pass == PassType_Basic)
1.113 + {
1.114 + v = *(Vector **)((unsigned char *)buffer + sizeof(Vector *));
1.115 + } else if (pass == PassType_Object) {
1.116 + v = (Vector *)buffer;
1.117 + }
1.118 +
1.119 + cell_t *addr;
1.120 + pContext->LocalToPhysAddr(param, &addr);
1.121 +
1.122 + addr[0] = v->x;
1.123 + addr[1] = v->y;
1.124 + addr[2] = v->z;
1.125 +
1.126 + return Data_Okay;
1.127 + }
1.128 + case Valve_QAngle:
1.129 + {
1.130 + QAngle *q = NULL;
1.131 +
1.132 + if (pass == PassType_Basic)
1.133 + {
1.134 + q = *(QAngle **)((unsigned char *)buffer + sizeof(QAngle *));
1.135 + } else if (pass == PassType_Object) {
1.136 + q = (QAngle *)buffer;
1.137 + }
1.138 +
1.139 + cell_t *addr;
1.140 + pContext->LocalToPhysAddr(param, &addr);
1.141 +
1.142 + addr[0] = q->x;
1.143 + addr[1] = q->y;
1.144 + addr[2] = q->z;
1.145 +
1.146 + return Data_Okay;
1.147 + }
1.148 + case Valve_CBaseEntity:
1.149 + case Valve_CBasePlayer:
1.150 + {
1.151 + cell_t *addr;
1.152 + pContext->LocalToPhysAddr(param, &addr);
1.153 +
1.154 + CBaseEntity *pEntity = *(CBaseEntity **)buffer;
1.155 + if (pEntity)
1.156 + {
1.157 + edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
1.158 + *addr = engine->IndexOfEdict(pEdict);
1.159 + } else {
1.160 + *addr = -1;
1.161 + }
1.162 +
1.163 + return Data_Okay;
1.164 + }
1.165 + case Valve_Edict:
1.166 + {
1.167 + cell_t *addr;
1.168 + pContext->LocalToPhysAddr(param, &addr);
1.169 +
1.170 + edict_t *pEdict = *(edict_t **)buffer;
1.171 + if (pEdict)
1.172 + {
1.173 + *addr = engine->IndexOfEdict(pEdict);
1.174 + } else {
1.175 + *addr = -1;
1.176 + }
1.177 +
1.178 + return Data_Okay;
1.179 + }
1.180 + case Valve_POD:
1.181 + case Valve_Float:
1.182 + {
1.183 + cell_t *addr;
1.184 + pContext->LocalToPhysAddr(param, &addr);
1.185 +
1.186 + *addr = *(cell_t *)buffer;
1.187 +
1.188 + return Data_Okay;
1.189 + }
1.190 + }
1.191 +
1.192 + return Data_Fail;
1.193 +}
1.194 +
1.195 +DataStatus DecodeValveParam(IPluginContext *pContext,
1.196 + cell_t param,
1.197 + ValveType vtype,
1.198 + unsigned int vflags,
1.199 + PassType type,
1.200 + void *buffer)
1.201 +{
1.202 + switch (vtype)
1.203 + {
1.204 + case Valve_Vector:
1.205 + {
1.206 + cell_t *addr;
1.207 + int err;
1.208 + err = pContext->LocalToPhysAddr(param, &addr);
1.209 +
1.210 + unsigned char *mem = (unsigned char *)buffer;
1.211 + if (type == PassType_Basic)
1.212 + {
1.213 + /* Store the object in the next N bytes, and store
1.214 + * a pointer to that object right beforehand.
1.215 + */
1.216 + Vector **realPtr = (Vector **)buffer;
1.217 +
1.218 + if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
1.219 + {
1.220 + if (vflags & VDECODE_FLAG_ALLOWNULL)
1.221 + {
1.222 + *realPtr = NULL;
1.223 + return Data_Okay;
1.224 + } else {
1.225 + pContext->ThrowNativeError("NULL not allowed");
1.226 + return Data_Fail;
1.227 + }
1.228 + } else {
1.229 + mem += sizeof(Vector *);
1.230 + *realPtr = (Vector *)mem;
1.231 + }
1.232 + }
1.233 +
1.234 + if (err != SP_ERROR_NONE)
1.235 + {
1.236 + pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
1.237 + return Data_Fail;
1.238 + }
1.239 +
1.240 + /* Use placement new to initialize the object cleanly
1.241 + * This has no destructor so we don't need to do
1.242 + * DestroyValveParam() or something :]
1.243 + */
1.244 + Vector *v = new (mem) Vector(
1.245 + sp_ctof(addr[0]),
1.246 + sp_ctof(addr[1]),
1.247 + sp_ctof(addr[2]));
1.248 +
1.249 + return Data_Okay;
1.250 + }
1.251 + case Valve_QAngle:
1.252 + {
1.253 + cell_t *addr;
1.254 + int err;
1.255 + err = pContext->LocalToPhysAddr(param, &addr);
1.256 +
1.257 + unsigned char *mem = (unsigned char *)buffer;
1.258 + if (type == PassType_Basic)
1.259 + {
1.260 + /* Store the object in the next N bytes, and store
1.261 + * a pointer to that object right beforehand.
1.262 + */
1.263 + QAngle **realPtr = (QAngle **)buffer;
1.264 +
1.265 + if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
1.266 + {
1.267 + if (!(vflags & VDECODE_FLAG_ALLOWNULL))
1.268 + {
1.269 + pContext->ThrowNativeError("NULL not allowed");
1.270 + return Data_Fail;
1.271 + } else {
1.272 + *realPtr = NULL;
1.273 + return Data_Okay;
1.274 + }
1.275 + } else {
1.276 + mem += sizeof(QAngle *);
1.277 + *realPtr = (QAngle *)mem;
1.278 + }
1.279 + }
1.280 +
1.281 + if (err != SP_ERROR_NONE)
1.282 + {
1.283 + pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
1.284 + return Data_Fail;
1.285 + }
1.286 +
1.287 + /* Use placement new to initialize the object cleanly
1.288 + * This has no destructor so we don't need to do
1.289 + * DestroyValveParam() or something :]
1.290 + */
1.291 + QAngle *v = new (mem) QAngle(
1.292 + sp_ctof(addr[0]),
1.293 + sp_ctof(addr[1]),
1.294 + sp_ctof(addr[2]));
1.295 +
1.296 + return Data_Okay;
1.297 + }
1.298 + case Valve_CBasePlayer:
1.299 + {
1.300 + edict_t *pEdict;
1.301 + if (vflags & VDECODE_FLAG_BYREF)
1.302 + {
1.303 + cell_t *addr;
1.304 + pContext->LocalToPhysAddr(param, &addr);
1.305 + param = *addr;
1.306 + }
1.307 + if (param >= 1 && param <= playerhelpers->GetMaxClients())
1.308 + {
1.309 + IGamePlayer *player = playerhelpers->GetGamePlayer(param);
1.310 + if ((vflags & VDECODE_FLAG_ALLOWNOTINGAME)
1.311 + && !player->IsConnected())
1.312 + {
1.313 + pContext->ThrowNativeError("Client %d is not connected", param);
1.314 + return Data_Fail;
1.315 + } else if (!player->IsInGame()) {
1.316 + pContext->ThrowNativeError("Client %d is not in game", param);
1.317 + return Data_Fail;
1.318 + }
1.319 + pEdict = player->GetEdict();
1.320 + } else if (param == -1) {
1.321 + if (vflags & VDECODE_FLAG_ALLOWNULL)
1.322 + {
1.323 + pEdict = NULL;
1.324 + } else {
1.325 + pContext->ThrowNativeError("NULL not allowed");
1.326 + return Data_Fail;
1.327 + }
1.328 + } else if (param == 0) {
1.329 + if (vflags & VDECODE_FLAG_ALLOWWORLD)
1.330 + {
1.331 + pEdict = engine->PEntityOfEntIndex(0);
1.332 + } else {
1.333 + pContext->ThrowNativeError("World not allowed");
1.334 + return Data_Fail;
1.335 + }
1.336 + } else {
1.337 + pContext->ThrowNativeError("Entity index %d is not a valid client", param);
1.338 + return Data_Fail;
1.339 + }
1.340 + CBaseEntity *pEntity;
1.341 + if (pEdict)
1.342 + {
1.343 + IServerUnknown *pUnknown = pEdict->GetUnknown();
1.344 + if (!pUnknown)
1.345 + {
1.346 + pContext->ThrowNativeError("Entity %d is a not an IServerUnknown");
1.347 + return Data_Fail;
1.348 + }
1.349 + pEntity = pUnknown->GetBaseEntity();
1.350 + if (!pEntity)
1.351 + {
1.352 + pContext->ThrowNativeError("Entity %d is not a CBaseEntity");
1.353 + return Data_Fail;
1.354 + }
1.355 + } else {
1.356 + pEdict = NULL;
1.357 + }
1.358 +
1.359 + CBaseEntity **ebuf = (CBaseEntity **)buffer;
1.360 + *ebuf = pEntity;
1.361 +
1.362 + return Data_Okay;
1.363 + }
1.364 + case Valve_CBaseEntity:
1.365 + {
1.366 + edict_t *pEdict;
1.367 + if (vflags & VDECODE_FLAG_BYREF)
1.368 + {
1.369 + cell_t *addr;
1.370 + pContext->LocalToPhysAddr(param, &addr);
1.371 + param = *addr;
1.372 + }
1.373 + if (param >= 1 && param <= playerhelpers->GetMaxClients())
1.374 + {
1.375 + IGamePlayer *player = playerhelpers->GetGamePlayer(param);
1.376 + if ((vflags & VDECODE_FLAG_ALLOWNOTINGAME)
1.377 + && !player->IsConnected())
1.378 + {
1.379 + pContext->ThrowNativeError("Client %d is not connected", param);
1.380 + return Data_Fail;
1.381 + } else if (!player->IsInGame()) {
1.382 + pContext->ThrowNativeError("Client %d is not in game", param);
1.383 + return Data_Fail;
1.384 + }
1.385 + pEdict = player->GetEdict();
1.386 + } else if (param == -1) {
1.387 + if (vflags & VDECODE_FLAG_ALLOWNULL)
1.388 + {
1.389 + pEdict = NULL;
1.390 + } else {
1.391 + pContext->ThrowNativeError("NULL not allowed");
1.392 + return Data_Fail;
1.393 + }
1.394 + } else if (param == 0) {
1.395 + if (vflags & VDECODE_FLAG_ALLOWWORLD)
1.396 + {
1.397 + pEdict = engine->PEntityOfEntIndex(0);
1.398 + } else {
1.399 + pContext->ThrowNativeError("World not allowed");
1.400 + return Data_Fail;
1.401 + }
1.402 + } else {
1.403 + pEdict = engine->PEntityOfEntIndex(param);
1.404 + if (!pEdict || pEdict->IsFree())
1.405 + {
1.406 + pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
1.407 + return Data_Fail;
1.408 + }
1.409 + }
1.410 + CBaseEntity *pEntity;
1.411 + if (pEdict)
1.412 + {
1.413 + IServerUnknown *pUnknown = pEdict->GetUnknown();
1.414 + if (!pUnknown)
1.415 + {
1.416 + pContext->ThrowNativeError("Entity %d is a not an IServerUnknown");
1.417 + return Data_Fail;
1.418 + }
1.419 + pEntity = pUnknown->GetBaseEntity();
1.420 + if (!pEntity)
1.421 + {
1.422 + pContext->ThrowNativeError("Entity %d is not a CBaseEntity");
1.423 + return Data_Fail;
1.424 + }
1.425 + } else {
1.426 + pEdict = NULL;
1.427 + }
1.428 +
1.429 + CBaseEntity **ebuf = (CBaseEntity **)buffer;
1.430 + *ebuf = pEntity;
1.431 +
1.432 + return Data_Okay;
1.433 + }
1.434 + case Valve_Edict:
1.435 + {
1.436 + edict_t *pEdict;
1.437 + if (vflags & VDECODE_FLAG_BYREF)
1.438 + {
1.439 + cell_t *addr;
1.440 + pContext->LocalToPhysAddr(param, &addr);
1.441 + param = *addr;
1.442 + }
1.443 + if (param >= 1 && param <= playerhelpers->GetMaxClients())
1.444 + {
1.445 + IGamePlayer *player = playerhelpers->GetGamePlayer(param);
1.446 + if ((vflags & VDECODE_FLAG_ALLOWNOTINGAME)
1.447 + && !player->IsConnected())
1.448 + {
1.449 + pContext->ThrowNativeError("Client %d is not connected", param);
1.450 + return Data_Fail;
1.451 + } else if (!player->IsInGame()) {
1.452 + pContext->ThrowNativeError("Client %d is not in game", param);
1.453 + return Data_Fail;
1.454 + }
1.455 + pEdict = player->GetEdict();
1.456 + } else if (param == -1) {
1.457 + if (vflags & VDECODE_FLAG_ALLOWNULL)
1.458 + {
1.459 + pEdict = NULL;
1.460 + } else {
1.461 + pContext->ThrowNativeError("NULL not allowed");
1.462 + return Data_Fail;
1.463 + }
1.464 + } else if (param == 0) {
1.465 + if (vflags & VDECODE_FLAG_ALLOWWORLD)
1.466 + {
1.467 + pEdict = engine->PEntityOfEntIndex(0);
1.468 + } else {
1.469 + pContext->ThrowNativeError("World not allowed");
1.470 + return Data_Fail;
1.471 + }
1.472 + } else {
1.473 + pEdict = engine->PEntityOfEntIndex(param);
1.474 + if (!pEdict || pEdict->IsFree())
1.475 + {
1.476 + pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
1.477 + return Data_Fail;
1.478 + }
1.479 + }
1.480 +
1.481 + edict_t **ebuf = (edict_t **)buffer;
1.482 + *ebuf = pEdict;
1.483 +
1.484 + return Data_Okay;
1.485 + }
1.486 + case Valve_POD:
1.487 + case Valve_Float:
1.488 + {
1.489 + if (vflags & VDECODE_FLAG_BYREF)
1.490 + {
1.491 + cell_t *addr;
1.492 + pContext->LocalToPhysAddr(param, &addr);
1.493 + param = *addr;
1.494 + }
1.495 + *(cell_t *)buffer = param;
1.496 + return Data_Okay;
1.497 + }
1.498 + case Valve_String:
1.499 + {
1.500 + char *addr;
1.501 + pContext->LocalToString(param, &addr);
1.502 + *(char **)buffer = addr;
1.503 + return Data_Okay;
1.504 + }
1.505 + }
1.506 +
1.507 + return Data_Fail;
1.508 +}