Added preliminary support for Left 4 Dead; some things may not yet work.
3 * =============================================================================
4 * SourceMod SDKTools Extension
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "smsdk_ext.h"
33 #include "extension.h"
35 #include "vcallbuilder.h"
37 using namespace SourceMod;
38 using namespace SourcePawn;
41 * For object pointers, the data looks like this instead:
42 * 4 bytes: POINTER TO LATER
43 * + bytes: Object internal data
45 * We use the virtual stack as extra fake stack space and create a temp object.
46 * If these objects had destructors, we'd need to fake destroy toom of course.
47 * Of course, BinTools only reads the first four bytes and passes the pointer.
50 size_t ValveParamToBinParam(ValveType type,
61 size_t mySize = sizeof(Vector *);
62 if (pass == PassType_Basic)
64 if (flags & PASSFLAG_BYREF)
68 info->type = PassType_Basic;
70 info->size = sizeof(Vector *);
71 mySize = sizeof(Vector);
73 } else if (pass == PassType_Object) {
74 info->type = PassType_Object;
75 info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
76 info->size = sizeof(Vector);
84 size_t mySize = sizeof(QAngle *);
85 if (pass == PassType_Basic)
87 if (flags & PASSFLAG_BYREF)
91 info->type = PassType_Basic;
93 info->size = sizeof(QAngle *);
94 mySize = sizeof(QAngle);
96 } else if (pass == PassType_Object) {
97 info->type = PassType_Object;
98 info->flags = flags | PASSFLAG_OASSIGNOP | PASSFLAG_OCTOR;
99 info->size = sizeof(QAngle);
105 case Valve_CBaseEntity:
106 case Valve_CBasePlayer:
110 if (pass != PassType_Basic || (flags & PASSFLAG_BYREF))
114 info->type = PassType_Basic;
116 info->size = sizeof(void *);
117 return sizeof(void *);
121 info->type = PassType_Basic;
123 if (flags & PASSFLAG_ASPOINTER)
126 info->size = sizeof(int *);
127 return sizeof(int *) + sizeof(int);
129 info->size = sizeof(int);
135 info->type = PassType_Basic;
137 if (flags & PASSFLAG_ASPOINTER)
140 info->size = sizeof(bool *);
141 return sizeof(bool *) + sizeof(bool);
143 info->size = sizeof(bool);
150 if (flags & PASSFLAG_ASPOINTER)
153 info->type = PassType_Basic;
154 info->size = sizeof(float *);
155 return sizeof(float *) + sizeof(float);
157 info->type = PassType_Float;
158 info->size = sizeof(float);
159 return sizeof(float);
167 DataStatus EncodeValveParam(IPluginContext *pContext,
169 const ValveCall *pCall,
170 const ValvePassInfo *data,
173 const void *buffer = (const unsigned char *)_buffer + data->offset;
180 if (data->type == PassType_Basic)
182 v = *(Vector **)buffer;
183 } else if (data->type == PassType_Object) {
184 v = (Vector *)buffer;
188 pContext->LocalToPhysAddr(param, &addr);
190 addr[0] = sp_ftoc(v->x);
191 addr[1] = sp_ftoc(v->y);
192 addr[2] = sp_ftoc(v->z);
200 if (data->type == PassType_Basic)
202 q = *(QAngle **)buffer;
203 } else if (data->type == PassType_Object) {
204 q = (QAngle *)buffer;
208 pContext->LocalToPhysAddr(param, &addr);
210 addr[0] = sp_ftoc(q->x);
211 addr[1] = sp_ftoc(q->y);
212 addr[2] = sp_ftoc(q->z);
216 case Valve_CBaseEntity:
217 case Valve_CBasePlayer:
220 pContext->LocalToPhysAddr(param, &addr);
222 CBaseEntity *pEntity = *(CBaseEntity **)buffer;
225 edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
226 *addr = IndexOfEdict(pEdict);
236 pContext->LocalToPhysAddr(param, &addr);
238 edict_t *pEdict = *(edict_t **)buffer;
241 *addr = IndexOfEdict(pEdict);
252 pContext->LocalToPhysAddr(param, &addr);
254 if (data->flags & PASSFLAG_ASPOINTER)
256 buffer = *(cell_t **)buffer;
259 *addr = *(cell_t *)buffer;
266 pContext->LocalToPhysAddr(param, &addr);
268 if (data->flags & PASSFLAG_ASPOINTER)
270 buffer = *(bool **)buffer;
273 *addr = *(bool *)buffer ? 1 : 0;
282 DataStatus DecodeValveParam(IPluginContext *pContext,
284 const ValveCall *pCall,
285 const ValvePassInfo *data,
288 void *buffer = (unsigned char *)_buffer + data->offset;
295 err = pContext->LocalToPhysAddr(param, &addr);
297 unsigned char *mem = (unsigned char *)buffer;
298 if (data->type == PassType_Basic)
300 /* Store the object in the next N bytes, and store
301 * a pointer to that object right beforehand.
303 Vector **realPtr = (Vector **)buffer;
305 if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
307 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
312 pContext->ThrowNativeError("NULL not allowed");
316 mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
317 *realPtr = (Vector *)mem;
321 if (err != SP_ERROR_NONE)
323 pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
327 /* Use placement new to initialize the object cleanly
328 * This has no destructor so we don't need to do
329 * DestroyValveParam() or something :]
331 Vector *v = new (mem) Vector(
342 err = pContext->LocalToPhysAddr(param, &addr);
344 unsigned char *mem = (unsigned char *)buffer;
345 if (data->type == PassType_Basic)
347 /* Store the object in the next N bytes, and store
348 * a pointer to that object right beforehand.
350 QAngle **realPtr = (QAngle **)buffer;
352 if (addr == pContext->GetNullRef(SP_NULL_VECTOR))
354 if (!(data->decflags & VDECODE_FLAG_ALLOWNULL))
356 pContext->ThrowNativeError("NULL not allowed");
363 mem = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
364 *realPtr = (QAngle *)mem;
368 if (err != SP_ERROR_NONE)
370 pContext->ThrowNativeErrorEx(err, "Could not read plugin data");
374 /* Use placement new to initialize the object cleanly
375 * This has no destructor so we don't need to do
376 * DestroyValveParam() or something :]
378 QAngle *v = new (mem) QAngle(
385 case Valve_CBasePlayer:
388 if (data->decflags & VDECODE_FLAG_BYREF)
391 pContext->LocalToPhysAddr(param, &addr);
394 if (param >= 1 && param <= playerhelpers->GetMaxClients())
396 IGamePlayer *player = playerhelpers->GetGamePlayer(param);
397 if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
398 && !player->IsConnected())
400 pContext->ThrowNativeError("Client %d is not connected", param);
402 } else if (!player->IsInGame()) {
403 pContext->ThrowNativeError("Client %d is not in game", param);
406 pEdict = player->GetEdict();
407 } else if (param == -1) {
408 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
412 pContext->ThrowNativeError("NULL not allowed");
415 } else if (param == 0) {
416 if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
418 pEdict = PEntityOfEntIndex(0);
420 pContext->ThrowNativeError("World not allowed");
424 pContext->ThrowNativeError("Entity index %d is not a valid client", param);
427 CBaseEntity *pEntity = NULL;
430 IServerUnknown *pUnknown = pEdict->GetUnknown();
433 pContext->ThrowNativeError("Entity %d is a not an IServerUnknown", param);
436 pEntity = pUnknown->GetBaseEntity();
439 pContext->ThrowNativeError("Entity %d is not a CBaseEntity", param);
444 CBaseEntity **ebuf = (CBaseEntity **)buffer;
449 case Valve_CBaseEntity:
452 if (data->decflags & VDECODE_FLAG_BYREF)
455 pContext->LocalToPhysAddr(param, &addr);
458 if (param >= 1 && param <= playerhelpers->GetMaxClients())
460 IGamePlayer *player = playerhelpers->GetGamePlayer(param);
461 if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
462 && !player->IsConnected())
464 pContext->ThrowNativeError("Client %d is not connected", param);
466 } else if (!player->IsInGame()) {
467 pContext->ThrowNativeError("Client %d is not in game", param);
470 pEdict = player->GetEdict();
471 } else if (param == -1) {
472 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
476 pContext->ThrowNativeError("NULL not allowed");
479 } else if (param == 0) {
480 if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
482 pEdict = PEntityOfEntIndex(0);
484 pContext->ThrowNativeError("World not allowed");
488 pEdict = PEntityOfEntIndex(param);
489 if (!pEdict || pEdict->IsFree())
491 pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
495 CBaseEntity *pEntity = NULL;
498 IServerUnknown *pUnknown = pEdict->GetUnknown();
501 pContext->ThrowNativeError("Entity %d is a not an IServerUnknown", param);
504 pEntity = pUnknown->GetBaseEntity();
507 pContext->ThrowNativeError("Entity %d is not a CBaseEntity", param);
512 CBaseEntity **ebuf = (CBaseEntity **)buffer;
520 if (data->decflags & VDECODE_FLAG_BYREF)
523 pContext->LocalToPhysAddr(param, &addr);
526 if (param >= 1 && param <= playerhelpers->GetMaxClients())
528 IGamePlayer *player = playerhelpers->GetGamePlayer(param);
529 if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME)
530 && !player->IsConnected())
532 pContext->ThrowNativeError("Client %d is not connected", param);
534 } else if (!player->IsInGame()) {
535 pContext->ThrowNativeError("Client %d is not in game", param);
538 pEdict = player->GetEdict();
539 } else if (param == -1) {
540 if (data->decflags & VDECODE_FLAG_ALLOWNULL)
544 pContext->ThrowNativeError("NULL not allowed");
547 } else if (param == 0) {
548 if (data->decflags & VDECODE_FLAG_ALLOWWORLD)
550 pEdict = PEntityOfEntIndex(0);
552 pContext->ThrowNativeError("World not allowed");
556 pEdict = PEntityOfEntIndex(param);
557 if (!pEdict || pEdict->IsFree())
559 pContext->ThrowNativeError("Entity %d is not valid or is freed", param);
564 edict_t **ebuf = (edict_t **)buffer;
572 if (data->decflags & VDECODE_FLAG_BYREF)
575 pContext->LocalToPhysAddr(param, &addr);
578 if (data->flags & PASSFLAG_ASPOINTER)
580 *(void **)buffer = (unsigned char *)_buffer + pCall->stackEnd + data->obj_offset;
581 buffer = *(void **)buffer;
583 *(cell_t *)buffer = param;
588 if (data->decflags & VDECODE_FLAG_BYREF)
591 pContext->LocalToPhysAddr(param, &addr);
594 if (data->flags & PASSFLAG_ASPOINTER)
596 *(bool **)buffer = (bool *)((unsigned char *)_buffer + pCall->stackEnd + data->obj_offset);
597 buffer = *(bool **)buffer;
599 *(bool *)buffer = param ? true : false;
605 pContext->LocalToString(param, &addr);
606 *(char **)buffer = addr;