4 #include "vcallbuilder.h"
6 using namespace SourceMod;
7 using namespace SourcePawn;
10 * For object pointers, the data looks like this instead:
11 * 4 bytes: POINTER TO LATER
12 * + bytes: Object internal data
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.
19 size_t ValveParamToBinParam(ValveType type,
30 size_t mySize = sizeof(Vector *);
31 if (pass == PassType_Basic)
33 if (flags & PASSFLAG_BYREF)
37 info->type = PassType_Basic;
39 info->size = sizeof(Vector *);
40 mySize = sizeof(Vector);
42 } else if (pass == PassType_Object) {
43 info->type = PassType_Object;
44 info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
45 info->size = sizeof(Vector);
53 size_t mySize = sizeof(QAngle *);
54 if (pass == PassType_Basic)
56 if (flags & PASSFLAG_BYREF)
60 info->type = PassType_Basic;
62 info->size = sizeof(QAngle *);
63 mySize = sizeof(QAngle);
65 } else if (pass == PassType_Object) {
66 info->type = PassType_Object;
67 info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
68 info->size = sizeof(QAngle);
74 case Valve_CBaseEntity:
75 case Valve_CBasePlayer:
79 if (pass != PassType_Basic || (flags & PASSFLAG_BYREF))
83 info->type = PassType_Basic;
85 info->size = sizeof(void *);
86 return sizeof(void *);
90 info->type = PassType_Basic;
92 if (flags & PASSFLAG_ASPOINTER)
94 info->size = sizeof(int *);
95 return sizeof(int *) + sizeof(int);
97 info->size = sizeof(int);
103 info->type = PassType_Basic;
105 if (flags & PASSFLAG_ASPOINTER)
107 info->size = sizeof(bool *);
108 return sizeof(bool *) + sizeof(bool);
110 info->size = sizeof(bool);
116 info->type = PassType_Float;
118 if (flags & PASSFLAG_ASPOINTER)
120 info->size = sizeof(float *);
121 return sizeof(float *) + sizeof(float);
123 info->size = sizeof(float);
124 return sizeof(float);
132 DataStatus EncodeValveParam(IPluginContext *pContext,
134 const ValveCall *pCall,
135 const ValvePassInfo *data,
138 const void *buffer = (const unsigned char *)_buffer + data->offset;
145 if (data->type == PassType_Basic)
147 v = *(Vector **)((unsigned char *)buffer + sizeof(Vector *));
148 } else if (data->type == PassType_Object) {
149 v = (Vector *)buffer;
153 pContext->LocalToPhysAddr(param, &addr);
155 addr[0] = sp_ftoc(v->x);
156 addr[1] = sp_ftoc(v->y);
157 addr[2] = sp_ftoc(v->z);
165 if (data->type == PassType_Basic)
167 q = *(QAngle **)((unsigned char *)buffer + sizeof(QAngle *));
168 } else if (data->type == PassType_Object) {
169 q = (QAngle *)buffer;
173 pContext->LocalToPhysAddr(param, &addr);
175 addr[0] = sp_ftoc(q->x);
176 addr[1] = sp_ftoc(q->y);
177 addr[2] = sp_ftoc(q->z);
181 case Valve_CBaseEntity:
182 case Valve_CBasePlayer:
185 pContext->LocalToPhysAddr(param, &addr);
187 CBaseEntity *pEntity = *(CBaseEntity **)buffer;
190 edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
191 *addr = engine->IndexOfEdict(pEdict);
201 pContext->LocalToPhysAddr(param, &addr);
203 edict_t *pEdict = *(edict_t **)buffer;
206 *addr = engine->IndexOfEdict(pEdict);
217 pContext->LocalToPhysAddr(param, &addr);
219 if (data->flags & PASSFLAG_ASPOINTER)
221 buffer = (char *)buffer + sizeof(void *);
224 *addr = *(cell_t *)buffer;
231 pContext->LocalToPhysAddr(param, &addr);
233 if (data->flags & PASSFLAG_ASPOINTER)
235 buffer = (char *)buffer + sizeof(bool *);
238 *addr = *(bool *)buffer ? 1 : 0;
247 DataStatus DecodeValveParam(IPluginContext *pContext,
249 const ValveCall *pCall,
250 const ValvePassInfo *data,
253 void *buffer = (unsigned char *)_buffer + data->offset;
260 err = pContext->LocalToPhysAddr(param, &addr);
262 unsigned char *mem = (unsigned char *)buffer;
263 if (data->type == PassType_Basic)
265 /* Store the object in the next N bytes, and store
266 * a pointer to that object right beforehand.
268 Vector **realPtr = (Vector **)buffer;
270 if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
272 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
277 pContext->ThrowNativeError("NULL not allowed");
281 mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
282 *realPtr = (Vector *)mem;
286 if (err != SP_ERROR_NONE)
288 pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
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 :]
296 Vector *v = new (mem) Vector(
307 err = pContext->LocalToPhysAddr(param, &addr);
309 unsigned char *mem = (unsigned char *)buffer;
310 if (data->type == PassType_Basic)
312 /* Store the object in the next N bytes, and store
313 * a pointer to that object right beforehand.
315 QAngle **realPtr = (QAngle **)buffer;
317 if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
319 if (!(data->decflags & VDECODE_FLAG_ALLOWNULL))
321 pContext->ThrowNativeError("NULL not allowed");
328 mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
329 *realPtr = (QAngle *)mem;
333 if (err != SP_ERROR_NONE)
335 pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
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 :]
343 QAngle *v = new (mem) QAngle(
350 case Valve_CBasePlayer:
353 if (data->decflags & VDECODE_FLAG_BYREF)
356 pContext->LocalToPhysAddr(param, &addr);
359 if (param >= 1 && param <= playerhelpers->GetMaxClients())
361 IGamePlayer *player = playerhelpers->GetGamePlayer(param);
362 if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
363 && !player->IsConnected())
365 pContext->ThrowNativeError("Client %d is not connected", param);
367 } else if (!player->IsInGame()) {
368 pContext->ThrowNativeError("Client %d is not in game", param);
371 pEdict = player->GetEdict();
372 } else if (param == -1) {
373 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
377 pContext->ThrowNativeError("NULL not allowed");
380 } else if (param == 0) {
381 if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
383 pEdict = engine->PEntityOfEntIndex(0);
385 pContext->ThrowNativeError("World not allowed");
389 pContext->ThrowNativeError("Entity index %d is not a valid client", param);
392 CBaseEntity *pEntity = NULL;
395 IServerUnknown *pUnknown = pEdict->GetUnknown();
398 pContext->ThrowNativeError("Entity %d is a not an IServerUnknown");
401 pEntity = pUnknown->GetBaseEntity();
404 pContext->ThrowNativeError("Entity %d is not a CBaseEntity");
409 CBaseEntity **ebuf = (CBaseEntity **)buffer;
414 case Valve_CBaseEntity:
417 if (data->decflags & VDECODE_FLAG_BYREF)
420 pContext->LocalToPhysAddr(param, &addr);
423 if (param >= 1 && param <= playerhelpers->GetMaxClients())
425 IGamePlayer *player = playerhelpers->GetGamePlayer(param);
426 if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
427 && !player->IsConnected())
429 pContext->ThrowNativeError("Client %d is not connected", param);
431 } else if (!player->IsInGame()) {
432 pContext->ThrowNativeError("Client %d is not in game", param);
435 pEdict = player->GetEdict();
436 } else if (param == -1) {
437 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
441 pContext->ThrowNativeError("NULL not allowed");
444 } else if (param == 0) {
445 if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
447 pEdict = engine->PEntityOfEntIndex(0);
449 pContext->ThrowNativeError("World not allowed");
453 pEdict = engine->PEntityOfEntIndex(param);
454 if (!pEdict || pEdict->IsFree())
456 pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
460 CBaseEntity *pEntity = NULL;
463 IServerUnknown *pUnknown = pEdict->GetUnknown();
466 pContext->ThrowNativeError("Entity %d is a not an IServerUnknown");
469 pEntity = pUnknown->GetBaseEntity();
472 pContext->ThrowNativeError("Entity %d is not a CBaseEntity");
477 CBaseEntity **ebuf = (CBaseEntity **)buffer;
485 if (data->decflags & VDECODE_FLAG_BYREF)
488 pContext->LocalToPhysAddr(param, &addr);
491 if (param >= 1 && param <= playerhelpers->GetMaxClients())
493 IGamePlayer *player = playerhelpers->GetGamePlayer(param);
494 if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
495 && !player->IsConnected())
497 pContext->ThrowNativeError("Client %d is not connected", param);
499 } else if (!player->IsInGame()) {
500 pContext->ThrowNativeError("Client %d is not in game", param);
503 pEdict = player->GetEdict();
504 } else if (param == -1) {
505 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
509 pContext->ThrowNativeError("NULL not allowed");
512 } else if (param == 0) {
513 if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
515 pEdict = engine->PEntityOfEntIndex(0);
517 pContext->ThrowNativeError("World not allowed");
521 pEdict = engine->PEntityOfEntIndex(param);
522 if (!pEdict || pEdict->IsFree())
524 pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
529 edict_t **ebuf = (edict_t **)buffer;
537 if (data->decflags & VDECODE_FLAG_BYREF)
540 pContext->LocalToPhysAddr(param, &addr);
543 if (data->flags & PASSFLAG_ASPOINTER)
545 *(void **)buffer = (char *)buffer + sizeof(void *);
546 buffer = *(void **)buffer;
548 *(cell_t *)buffer = param;
553 if (data->decflags & VDECODE_FLAG_BYREF)
556 pContext->LocalToPhysAddr(param, &addr);
559 if (data->flags & PASSFLAG_ASPOINTER)
561 *(bool **)buffer = (bool *)((char *)buffer + sizeof(bool *));
562 buffer = *(bool **)buffer;
564 *(bool *)buffer = param ? true : false;
570 pContext->LocalToString(param, &addr);
571 *(char **)buffer = addr;