3 * ================================================================
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 "sm_globals.h"
34 #include "sourcemod.h"
35 #include "sourcemm_api.h"
36 #include "server_class.h"
37 #include "PlayerManager.h"
38 #include "HalfLife2.h"
39 #include "GameConfigs.h"
40 #include "sm_stringutil.h"
48 inline edict_t *GetEdict(cell_t num)
50 edict_t *pEdict = engine->PEntityOfEntIndex(num);
51 if (!pEdict || pEdict->IsFree())
55 if (num > 0 && num < g_Players.GetMaxClients())
57 CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
58 if (!pPlayer || !pPlayer->IsConnected())
66 inline edict_t *GetEntity(cell_t num, CBaseEntity **pData)
68 edict_t *pEdict = engine->PEntityOfEntIndex(num);
69 if (!pEdict || pEdict->IsFree())
73 if (num > 0 && num < g_Players.GetMaxClients())
75 CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
76 if (!pPlayer || !pPlayer->IsConnected())
82 if ((pUnk=pEdict->GetUnknown()) == NULL)
86 *pData = pUnk->GetBaseEntity();
91 datamap_t *VGetDataDescMap(CBaseEntity *pThisPtr, int offset)
93 void **this_ptr = *reinterpret_cast<void ***>(&pThisPtr);
94 void **vtable = *reinterpret_cast<void ***>(pThisPtr);
95 void *vfunc = vtable[offset];
99 datamap_t *(VEmptyClass::*mfpnew)();
100 #ifndef PLATFORM_POSIX
115 return (datamap_t *)(reinterpret_cast<VEmptyClass *>(this_ptr)->*u.mfpnew)();
118 inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity)
122 if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset)
127 return VGetDataDescMap(pEntity, offset);
130 /* :TODO: Move this! */
131 datamap_t *CHalfLife2::GetDataMap(CBaseEntity *pEntity)
133 return CBaseEntity_GetDataDescMap(pEntity);
136 static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params)
138 return gpGlobals->maxEntities;
141 static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params)
143 edict_t *pEdict = engine->CreateEdict();
150 return engine->IndexOfEdict(pEdict);
153 static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
155 edict_t *pEdict = engine->PEntityOfEntIndex(params[1]);
159 return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]);
162 engine->RemoveEdict(pEdict);
167 static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params)
169 edict_t *pEdict = GetEdict(params[1]);
176 /* Shouldn't be necessary... not sure though */
177 return pEdict->IsFree() ? 0 : 1;
180 static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
182 edict_t *pEdict = GetEdict(params[1]);
189 IServerUnknown *pUnknown = pEdict->GetUnknown();
195 CBaseEntity *pEntity = pUnknown->GetBaseEntity();
196 return (pEntity != NULL) ? 1 : 0;
199 static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
201 edict_t *pEdict = GetEdict(params[1]);
208 return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
211 static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
213 return engine->GetEntityCount();
216 static cell_t GetEdictFlags(IPluginContext *pContext, const cell_t *params)
218 edict_t *pEdict = GetEdict(params[1]);
222 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
225 return pEdict->m_fStateFlags;
228 static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params)
230 edict_t *pEdict = GetEdict(params[1]);
234 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
237 pEdict->m_fStateFlags = params[2];
242 static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params)
244 edict_t *pEdict = GetEdict(params[1]);
248 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
251 const char *cls = pEdict->GetClassName();
253 if (!cls || cls[0] == '\0')
258 pContext->StringToLocal(params[2], params[3], cls);
263 static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
265 edict_t *pEdict = GetEdict(params[1]);
269 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
272 IServerNetworkable *pNet = pEdict->GetNetworkable();
278 ServerClass *pClass = pNet->GetServerClass();
280 pContext->StringToLocal(params[2], params[3], pClass->GetName());
285 static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
287 CBaseEntity *pEntity;
288 edict_t *pEdict = GetEntity(params[1], &pEntity);
290 if (!pEdict || !pEntity)
292 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
295 int offset = params[2];
296 if (offset < 0 || offset > 32768)
298 return pContext->ThrowNativeError("Offset %d is invalid", offset);
304 return *(int *)((uint8_t *)pEntity + offset);
306 return *(short *)((uint8_t *)pEntity + offset);
308 return *((uint8_t *)pEntity + offset);
310 return pContext->ThrowNativeError("Integer size %d is invalid", params[3]);
314 static cell_t SetEntData(IPluginContext *pContext, const cell_t *params)
316 CBaseEntity *pEntity;
317 edict_t *pEdict = GetEntity(params[1], &pEntity);
319 if (!pEdict || !pEntity)
321 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
324 int offset = params[2];
325 if (offset < 0 || offset > 32768)
327 return pContext->ThrowNativeError("Offset %d is invalid", offset);
332 g_HL2.SetEdictStateChanged(pEdict, offset);
339 *(int *)((uint8_t *)pEntity + offset) = params[3];
344 *(short *)((uint8_t *)pEntity + offset) = params[3];
349 *((uint8_t *)pEntity + offset) = params[3];
353 return pContext->ThrowNativeError("Integer size %d is invalid", params[4]);
359 static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
361 CBaseEntity *pEntity;
362 edict_t *pEdict = GetEntity(params[1], &pEntity);
364 if (!pEdict || !pEntity)
366 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
369 int offset = params[2];
370 if (offset < 0 || offset > 32768)
372 return pContext->ThrowNativeError("Offset %d is invalid", offset);
375 float f = *(float *)((uint8_t *)pEntity + offset);
380 static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params)
382 CBaseEntity *pEntity;
383 edict_t *pEdict = GetEntity(params[1], &pEntity);
385 if (!pEdict || !pEntity)
387 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
390 int offset = params[2];
391 if (offset < 0 || offset > 32768)
393 return pContext->ThrowNativeError("Offset %d is invalid", offset);
396 *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
400 g_HL2.SetEdictStateChanged(pEdict, offset);
406 static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
408 CBaseEntity *pEntity;
409 edict_t *pEdict = GetEntity(params[1], &pEntity);
411 if (!pEdict || !pEntity)
413 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
416 int offset = params[2];
417 if (offset < 0 || offset > 32768)
419 return pContext->ThrowNativeError("Offset %d is invalid", offset);
422 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
425 pContext->LocalToPhysAddr(params[3], &vec);
427 vec[0] = sp_ftoc(v->x);
428 vec[1] = sp_ftoc(v->y);
429 vec[2] = sp_ftoc(v->z);
434 static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params)
436 CBaseEntity *pEntity;
437 edict_t *pEdict = GetEntity(params[1], &pEntity);
439 if (!pEdict || !pEntity)
441 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
444 int offset = params[2];
445 if (offset < 0 || offset > 32768)
447 return pContext->ThrowNativeError("Offset %d is invalid", offset);
450 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
453 pContext->LocalToPhysAddr(params[3], &vec);
455 v->x = sp_ctof(vec[0]);
456 v->y = sp_ctof(vec[1]);
457 v->z = sp_ctof(vec[2]);
461 g_HL2.SetEdictStateChanged(pEdict, offset);
467 static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
469 CBaseEntity *pEntity;
470 edict_t *pEdict = GetEntity(params[1], &pEntity);
472 if (!pEdict || !pEntity)
474 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
477 int offset = params[2];
478 if (offset < 0 || offset > 32768)
480 return pContext->ThrowNativeError("Offset %d is invalid", offset);
483 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
490 /* :TODO: check serial no.? */
492 return hndl.GetEntryIndex();
495 static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
497 CBaseEntity *pEntity;
498 edict_t *pEdict = GetEntity(params[1], &pEntity);
500 if (!pEdict || !pEntity)
502 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
505 int offset = params[2];
506 if (offset < 0 || offset > 32768)
508 return pContext->ThrowNativeError("Offset %d is invalid", offset);
511 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
517 edict_t *pEdict = GetEdict(params[3]);
520 return pContext->ThrowNativeError("Entity %d is invalid", params[3]);
522 IServerEntity *pEntOther = pEdict->GetIServerEntity();
528 g_HL2.SetEdictStateChanged(pEdict, offset);
534 static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
536 edict_t *pEdict = GetEdict(params[1]);
540 return pContext->ThrowNativeError("Edict %d is invalid", params[1]);
543 g_HL2.SetEdictStateChanged(pEdict, params[2]);
548 static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
551 pContext->LocalToString(params[1], &cls);
552 pContext->LocalToString(params[2], &prop);
554 SendProp *pSend = g_HL2.FindInSendTable(cls, prop);
561 return pSend->GetOffset();
564 static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
566 CBaseEntity *pEntity;
568 typedescription_t *td;
570 edict_t *pEdict = GetEntity(params[1], &pEntity);
572 if (!pEdict || !pEntity)
574 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
577 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
579 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
582 pContext->LocalToString(params[2], &offset);
583 if ((td=g_HL2.FindInDataMap(pMap, offset)) == NULL)
588 return td->fieldOffset[TD_OFFSET_NORMAL];
591 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
593 CBaseEntity *pEntity;
594 edict_t *pEdict = GetEntity(params[1], &pEntity);
596 if (!pEdict || !pEntity)
598 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
601 int offset = params[2];
602 if (offset < 0 || offset > 32768)
604 return pContext->ThrowNativeError("Offset %d is invalid", offset);
608 char *src = (char *)((uint8_t *)pEntity + offset);
609 pContext->StringToLocalUTF8(params[3], params[4], src, &len);
614 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
616 CBaseEntity *pEntity;
617 edict_t *pEdict = GetEntity(params[1], &pEntity);
619 if (!pEdict || !pEntity)
621 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
624 int offset = params[2];
625 if (offset < 0 || offset > 32768)
627 return pContext->ThrowNativeError("Offset %d is invalid", offset);
631 char *dest = (char *)((uint8_t *)pEntity + offset);
633 pContext->LocalToString(params[3], &src);
634 size_t len = strncopy(dest, src, params[4]);
638 g_HL2.SetEdictStateChanged(pEdict, offset);
644 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
646 CBaseEntity *pEntity;
649 edict_t *pEdict = GetEntity(params[1], &pEntity);
651 if (!pEdict || !pEntity)
653 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
661 typedescription_t *td;
662 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
664 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
666 pContext->LocalToString(params[3], &prop);
667 if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
669 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
671 if (td->fieldType != FIELD_CHARACTER)
673 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
675 offset = td->fieldOffset[TD_OFFSET_NORMAL];
681 IServerNetworkable *pNet = pEdict->GetNetworkable();
684 return pContext->ThrowNativeError("The edict is not networkable");
686 pContext->LocalToString(params[3], &prop);
687 SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
690 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
692 if (pSend->GetType() != DPT_String)
694 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
696 offset = pSend->GetOffset();
701 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
706 char *src = (char *)((uint8_t *)pEntity + offset);
707 pContext->StringToLocalUTF8(params[4], params[5], src, &len);
712 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
714 CBaseEntity *pEntity;
718 bool is_sendprop = false;
719 edict_t *pEdict = GetEntity(params[1], &pEntity);
721 if (!pEdict || !pEntity)
723 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
731 typedescription_t *td;
732 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
734 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
736 pContext->LocalToString(params[3], &prop);
737 if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
739 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
741 if (td->fieldType != FIELD_CHARACTER)
743 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
745 offset = td->fieldOffset[TD_OFFSET_NORMAL];
746 maxlen = td->fieldSize;
752 IServerNetworkable *pNet = pEdict->GetNetworkable();
755 return pContext->ThrowNativeError("The edict is not networkable");
757 pContext->LocalToString(params[3], &prop);
758 SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
761 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
763 if (pSend->GetType() != DPT_String)
765 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
767 offset = pSend->GetOffset();
768 maxlen = DT_MAX_STRING_BUFFERSIZE;
774 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
779 char *dest = (char *)((uint8_t *)pEntity + offset);
781 pContext->LocalToString(params[4], &src);
782 size_t len = strncopy(dest, src, maxlen);
786 g_HL2.SetEdictStateChanged(pEdict, offset);
792 REGISTER_NATIVES(entityNatives)
794 {"ChangeEdictState", ChangeEdictState},
795 {"CreateEdict", CreateEdict},
796 {"FindSendPropOffs", FindSendPropOffs},
797 {"GetEdictClassname", GetEdictClassname},
798 {"GetEdictFlags", GetEdictFlags},
799 {"GetEntData", GetEntData},
800 {"GetEntDataEnt", GetEntDataEnt},
801 {"GetEntDataFloat", GetEntDataFloat},
802 {"GetEntDataVector", GetEntDataVector},
803 {"GetEntityCount", GetEntityCount},
804 {"GetEntityNetClass", GetEntityNetClass},
805 {"GetMaxEntities", GetMaxEntities},
806 {"IsEntNetworkable", IsEntNetworkable},
807 {"IsValidEdict", IsValidEdict},
808 {"IsValidEntity", IsValidEntity},
809 {"RemoveEdict", RemoveEdict},
810 {"SetEdictFlags", SetEdictFlags},
811 {"SetEntData", SetEntData},
812 {"SetEntDataEnt", SetEntDataEnt},
813 {"SetEntDataFloat", SetEntDataFloat},
814 {"SetEntDataVector", SetEntDataVector},
815 {"FindDataMapOffs", FindDataMapOffs},
816 {"GetEntDataString", GetEntDataString},
817 {"SetEntDataString", SetEntDataString},
818 {"GetEntPropString", GetEntPropString},
819 {"SetEntPropString", SetEntPropString},