3 * ================================================================
4 * SourceMod SDKTools Extension
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * ================================================================
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.
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.
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/>.
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>.
33 #include "smsdk_ext.h"
34 #include "extension.h"
36 #include "vcallbuilder.h"
38 using namespace SourceMod;
39 using namespace SourcePawn;
42 * For object pointers, the data looks like this instead:
43 * 4 bytes: POINTER TO LATER
44 * + bytes: Object internal data
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.
51 size_t ValveParamToBinParam(ValveType type,
62 size_t mySize = sizeof(Vector *);
63 if (pass == PassType_Basic)
65 if (flags & PASSFLAG_BYREF)
69 info->type = PassType_Basic;
71 info->size = sizeof(Vector *);
72 mySize = sizeof(Vector);
74 } else if (pass == PassType_Object) {
75 info->type = PassType_Object;
76 info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
77 info->size = sizeof(Vector);
85 size_t mySize = sizeof(QAngle *);
86 if (pass == PassType_Basic)
88 if (flags & PASSFLAG_BYREF)
92 info->type = PassType_Basic;
94 info->size = sizeof(QAngle *);
95 mySize = sizeof(QAngle);
97 } else if (pass == PassType_Object) {
98 info->type = PassType_Object;
99 info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
100 info->size = sizeof(QAngle);
106 case Valve_CBaseEntity:
107 case Valve_CBasePlayer:
111 if (pass != PassType_Basic || (flags & PASSFLAG_BYREF))
115 info->type = PassType_Basic;
117 info->size = sizeof(void *);
118 return sizeof(void *);
122 info->type = PassType_Basic;
124 if (flags & PASSFLAG_ASPOINTER)
127 info->size = sizeof(int *);
128 return sizeof(int *) + sizeof(int);
130 info->size = sizeof(int);
136 info->type = PassType_Basic;
138 if (flags & PASSFLAG_ASPOINTER)
141 info->size = sizeof(bool *);
142 return sizeof(bool *) + sizeof(bool);
144 info->size = sizeof(bool);
151 if (flags & PASSFLAG_ASPOINTER)
154 info->type = PassType_Basic;
155 info->size = sizeof(float *);
156 return sizeof(float *) + sizeof(float);
158 info->type = PassType_Float;
159 info->size = sizeof(float);
160 return sizeof(float);
168 DataStatus EncodeValveParam(IPluginContext *pContext,
170 const ValveCall *pCall,
171 const ValvePassInfo *data,
174 const void *buffer = (const unsigned char *)_buffer + data->offset;
181 if (data->type == PassType_Basic)
183 v = *(Vector **)buffer;
184 } else if (data->type == PassType_Object) {
185 v = (Vector *)buffer;
189 pContext->LocalToPhysAddr(param, &addr);
191 addr[0] = sp_ftoc(v->x);
192 addr[1] = sp_ftoc(v->y);
193 addr[2] = sp_ftoc(v->z);
201 if (data->type == PassType_Basic)
203 q = *(QAngle **)buffer;
204 } else if (data->type == PassType_Object) {
205 q = (QAngle *)buffer;
209 pContext->LocalToPhysAddr(param, &addr);
211 addr[0] = sp_ftoc(q->x);
212 addr[1] = sp_ftoc(q->y);
213 addr[2] = sp_ftoc(q->z);
217 case Valve_CBaseEntity:
218 case Valve_CBasePlayer:
221 pContext->LocalToPhysAddr(param, &addr);
223 CBaseEntity *pEntity = *(CBaseEntity **)buffer;
226 edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
227 *addr = engine->IndexOfEdict(pEdict);
237 pContext->LocalToPhysAddr(param, &addr);
239 edict_t *pEdict = *(edict_t **)buffer;
242 *addr = engine->IndexOfEdict(pEdict);
253 pContext->LocalToPhysAddr(param, &addr);
255 if (data->flags & PASSFLAG_ASPOINTER)
257 buffer = *(cell_t **)buffer;
260 *addr = *(cell_t *)buffer;
267 pContext->LocalToPhysAddr(param, &addr);
269 if (data->flags & PASSFLAG_ASPOINTER)
271 buffer = *(bool **)buffer;
274 *addr = *(bool *)buffer ? 1 : 0;
283 DataStatus DecodeValveParam(IPluginContext *pContext,
285 const ValveCall *pCall,
286 const ValvePassInfo *data,
289 void *buffer = (unsigned char *)_buffer + data->offset;
296 err = pContext->LocalToPhysAddr(param, &addr);
298 unsigned char *mem = (unsigned char *)buffer;
299 if (data->type == PassType_Basic)
301 /* Store the object in the next N bytes, and store
302 * a pointer to that object right beforehand.
304 Vector **realPtr = (Vector **)buffer;
306 if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
308 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
313 pContext->ThrowNativeError("NULL not allowed");
317 mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
318 *realPtr = (Vector *)mem;
322 if (err != SP_ERROR_NONE)
324 pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
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 :]
332 Vector *v = new (mem) Vector(
343 err = pContext->LocalToPhysAddr(param, &addr);
345 unsigned char *mem = (unsigned char *)buffer;
346 if (data->type == PassType_Basic)
348 /* Store the object in the next N bytes, and store
349 * a pointer to that object right beforehand.
351 QAngle **realPtr = (QAngle **)buffer;
353 if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
355 if (!(data->decflags & VDECODE_FLAG_ALLOWNULL))
357 pContext->ThrowNativeError("NULL not allowed");
364 mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
365 *realPtr = (QAngle *)mem;
369 if (err != SP_ERROR_NONE)
371 pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
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 :]
379 QAngle *v = new (mem) QAngle(
386 case Valve_CBasePlayer:
389 if (data->decflags & VDECODE_FLAG_BYREF)
392 pContext->LocalToPhysAddr(param, &addr);
395 if (param >= 1 && param <= playerhelpers->GetMaxClients())
397 IGamePlayer *player = playerhelpers->GetGamePlayer(param);
398 if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
399 && !player->IsConnected())
401 pContext->ThrowNativeError("Client %d is not connected", param);
403 } else if (!player->IsInGame()) {
404 pContext->ThrowNativeError("Client %d is not in game", param);
407 pEdict = player->GetEdict();
408 } else if (param == -1) {
409 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
413 pContext->ThrowNativeError("NULL not allowed");
416 } else if (param == 0) {
417 if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
419 pEdict = engine->PEntityOfEntIndex(0);
421 pContext->ThrowNativeError("World not allowed");
425 pContext->ThrowNativeError("Entity index %d is not a valid client", param);
428 CBaseEntity *pEntity = NULL;
431 IServerUnknown *pUnknown = pEdict->GetUnknown();
434 pContext->ThrowNativeError("Entity %d is a not an IServerUnknown");
437 pEntity = pUnknown->GetBaseEntity();
440 pContext->ThrowNativeError("Entity %d is not a CBaseEntity");
445 CBaseEntity **ebuf = (CBaseEntity **)buffer;
450 case Valve_CBaseEntity:
453 if (data->decflags & VDECODE_FLAG_BYREF)
456 pContext->LocalToPhysAddr(param, &addr);
459 if (param >= 1 && param <= playerhelpers->GetMaxClients())
461 IGamePlayer *player = playerhelpers->GetGamePlayer(param);
462 if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
463 && !player->IsConnected())
465 pContext->ThrowNativeError("Client %d is not connected", param);
467 } else if (!player->IsInGame()) {
468 pContext->ThrowNativeError("Client %d is not in game", param);
471 pEdict = player->GetEdict();
472 } else if (param == -1) {
473 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
477 pContext->ThrowNativeError("NULL not allowed");
480 } else if (param == 0) {
481 if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
483 pEdict = engine->PEntityOfEntIndex(0);
485 pContext->ThrowNativeError("World not allowed");
489 pEdict = engine->PEntityOfEntIndex(param);
490 if (!pEdict || pEdict->IsFree())
492 pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
496 CBaseEntity *pEntity = NULL;
499 IServerUnknown *pUnknown = pEdict->GetUnknown();
502 pContext->ThrowNativeError("Entity %d is a not an IServerUnknown");
505 pEntity = pUnknown->GetBaseEntity();
508 pContext->ThrowNativeError("Entity %d is not a CBaseEntity");
513 CBaseEntity **ebuf = (CBaseEntity **)buffer;
521 if (data->decflags & VDECODE_FLAG_BYREF)
524 pContext->LocalToPhysAddr(param, &addr);
527 if (param >= 1 && param <= playerhelpers->GetMaxClients())
529 IGamePlayer *player = playerhelpers->GetGamePlayer(param);
530 if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
531 && !player->IsConnected())
533 pContext->ThrowNativeError("Client %d is not connected", param);
535 } else if (!player->IsInGame()) {
536 pContext->ThrowNativeError("Client %d is not in game", param);
539 pEdict = player->GetEdict();
540 } else if (param == -1) {
541 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
545 pContext->ThrowNativeError("NULL not allowed");
548 } else if (param == 0) {
549 if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
551 pEdict = engine->PEntityOfEntIndex(0);
553 pContext->ThrowNativeError("World not allowed");
557 pEdict = engine->PEntityOfEntIndex(param);
558 if (!pEdict || pEdict->IsFree())
560 pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
565 edict_t **ebuf = (edict_t **)buffer;
573 if (data->decflags & VDECODE_FLAG_BYREF)
576 pContext->LocalToPhysAddr(param, &addr);
579 if (data->flags & PASSFLAG_ASPOINTER)
581 *(void **)buffer = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
582 buffer = *(void **)buffer;
584 *(cell_t *)buffer = param;
589 if (data->decflags & VDECODE_FLAG_BYREF)
592 pContext->LocalToPhysAddr(param, &addr);
595 if (data->flags & PASSFLAG_ASPOINTER)
597 *(bool **)buffer = (bool *)((unsigned char *)_buffer + pCall->stackEnd + data->obj_offset);
598 buffer = *(bool **)buffer;
600 *(bool *)buffer = param ? true : false;
606 pContext->LocalToString(param, &addr);
607 *(char **)buffer = addr;