3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
15 #include "sm_globals.h"
16 #include "sourcemod.h"
17 #include "sourcemm_api.h"
18 #include "server_class.h"
19 #include "PlayerManager.h"
20 #include "HalfLife2.h"
21 #include "GameConfigs.h"
22 #include "sm_stringutil.h"
30 inline edict_t *GetEdict(cell_t num)
32 edict_t *pEdict = engine->PEntityOfEntIndex(num);
33 if (!pEdict || pEdict->IsFree())
37 if (num > 0 && num < g_Players.GetMaxClients())
39 CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
40 if (!pPlayer || !pPlayer->IsConnected())
48 inline edict_t *GetEntity(cell_t num, CBaseEntity **pData)
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())
64 if ((pUnk=pEdict->GetUnknown()) == NULL)
68 *pData = pUnk->GetBaseEntity();
73 datamap_t *VGetDataDescMap(CBaseEntity *pThisPtr, int offset)
75 void **this_ptr = *reinterpret_cast<void ***>(&pThisPtr);
76 void **vtable = *reinterpret_cast<void ***>(pThisPtr);
77 void *vfunc = vtable[offset];
81 datamap_t *(VEmptyClass::*mfpnew)();
82 #ifndef PLATFORM_POSIX
97 return (datamap_t *)(reinterpret_cast<VEmptyClass *>(this_ptr)->*u.mfpnew)();
100 inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity)
104 if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset)
109 return VGetDataDescMap(pEntity, offset);
112 static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params)
114 return gpGlobals->maxEntities;
117 static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params)
119 edict_t *pEdict = engine->CreateEdict();
126 return engine->IndexOfEdict(pEdict);
129 static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
131 edict_t *pEdict = engine->PEntityOfEntIndex(params[1]);
135 return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]);
138 engine->RemoveEdict(pEdict);
143 static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params)
145 edict_t *pEdict = GetEdict(params[1]);
152 /* Shouldn't be necessary... not sure though */
153 return pEdict->IsFree() ? 0 : 1;
156 static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
158 edict_t *pEdict = GetEdict(params[1]);
165 IServerUnknown *pUnknown = pEdict->GetUnknown();
171 CBaseEntity *pEntity = pUnknown->GetBaseEntity();
172 return (pEntity != NULL) ? 1 : 0;
175 static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
177 edict_t *pEdict = GetEdict(params[1]);
184 return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
187 static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
189 return engine->GetEntityCount();
192 static cell_t GetEdictFlags(IPluginContext *pContext, const cell_t *params)
194 edict_t *pEdict = GetEdict(params[1]);
198 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
201 return pEdict->m_fStateFlags;
204 static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params)
206 edict_t *pEdict = GetEdict(params[1]);
210 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
213 pEdict->m_fStateFlags = params[2];
218 static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params)
220 edict_t *pEdict = GetEdict(params[1]);
224 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
227 const char *cls = pEdict->GetClassName();
229 if (!cls || cls[0] == '\0')
234 pContext->StringToLocal(params[2], params[3], cls);
239 static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
241 edict_t *pEdict = GetEdict(params[1]);
245 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
248 IServerNetworkable *pNet = pEdict->GetNetworkable();
254 ServerClass *pClass = pNet->GetServerClass();
256 pContext->StringToLocal(params[2], params[3], pClass->GetName());
261 static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
263 CBaseEntity *pEntity;
264 edict_t *pEdict = GetEntity(params[1], &pEntity);
266 if (!pEdict || !pEntity)
268 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
271 int offset = params[2];
272 if (offset < 0 || offset > 32768)
274 return pContext->ThrowNativeError("Offset %d is invalid", offset);
280 return *(int *)((uint8_t *)pEntity + offset);
282 return *(short *)((uint8_t *)pEntity + offset);
284 return *((uint8_t *)pEntity + offset);
286 return pContext->ThrowNativeError("Integer size %d is invalid", params[3]);
290 static cell_t SetEntData(IPluginContext *pContext, const cell_t *params)
292 CBaseEntity *pEntity;
293 edict_t *pEdict = GetEntity(params[1], &pEntity);
295 if (!pEdict || !pEntity)
297 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
300 int offset = params[2];
301 if (offset < 0 || offset > 32768)
303 return pContext->ThrowNativeError("Offset %d is invalid", offset);
308 g_HL2.SetEdictStateChanged(pEdict, offset);
315 *(int *)((uint8_t *)pEntity + offset) = params[3];
320 *(short *)((uint8_t *)pEntity + offset) = params[3];
325 *((uint8_t *)pEntity + offset) = params[3];
329 return pContext->ThrowNativeError("Integer size %d is invalid", params[4]);
335 static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
337 CBaseEntity *pEntity;
338 edict_t *pEdict = GetEntity(params[1], &pEntity);
340 if (!pEdict || !pEntity)
342 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
345 int offset = params[2];
346 if (offset < 0 || offset > 32768)
348 return pContext->ThrowNativeError("Offset %d is invalid", offset);
351 float f = *(float *)((uint8_t *)pEntity + offset);
356 static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params)
358 CBaseEntity *pEntity;
359 edict_t *pEdict = GetEntity(params[1], &pEntity);
361 if (!pEdict || !pEntity)
363 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
366 int offset = params[2];
367 if (offset < 0 || offset > 32768)
369 return pContext->ThrowNativeError("Offset %d is invalid", offset);
372 *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
376 g_HL2.SetEdictStateChanged(pEdict, offset);
382 static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
384 CBaseEntity *pEntity;
385 edict_t *pEdict = GetEntity(params[1], &pEntity);
387 if (!pEdict || !pEntity)
389 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
392 int offset = params[2];
393 if (offset < 0 || offset > 32768)
395 return pContext->ThrowNativeError("Offset %d is invalid", offset);
398 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
401 pContext->LocalToPhysAddr(params[3], &vec);
403 vec[0] = sp_ftoc(v->x);
404 vec[1] = sp_ftoc(v->y);
405 vec[2] = sp_ftoc(v->z);
410 static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params)
412 CBaseEntity *pEntity;
413 edict_t *pEdict = GetEntity(params[1], &pEntity);
415 if (!pEdict || !pEntity)
417 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
420 int offset = params[2];
421 if (offset < 0 || offset > 32768)
423 return pContext->ThrowNativeError("Offset %d is invalid", offset);
426 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
429 pContext->LocalToPhysAddr(params[3], &vec);
431 v->x = sp_ctof(vec[0]);
432 v->y = sp_ctof(vec[1]);
433 v->z = sp_ctof(vec[2]);
437 g_HL2.SetEdictStateChanged(pEdict, offset);
443 static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
445 CBaseEntity *pEntity;
446 edict_t *pEdict = GetEntity(params[1], &pEntity);
448 if (!pEdict || !pEntity)
450 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
453 int offset = params[2];
454 if (offset < 0 || offset > 32768)
456 return pContext->ThrowNativeError("Offset %d is invalid", offset);
459 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
466 /* :TODO: check serial no.? */
468 return hndl.GetEntryIndex();
471 static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
473 CBaseEntity *pEntity;
474 edict_t *pEdict = GetEntity(params[1], &pEntity);
476 if (!pEdict || !pEntity)
478 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
481 int offset = params[2];
482 if (offset < 0 || offset > 32768)
484 return pContext->ThrowNativeError("Offset %d is invalid", offset);
487 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
493 edict_t *pEdict = GetEdict(params[3]);
496 return pContext->ThrowNativeError("Entity %d is invalid", params[3]);
498 IServerEntity *pEntOther = pEdict->GetIServerEntity();
504 g_HL2.SetEdictStateChanged(pEdict, offset);
510 static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
512 edict_t *pEdict = GetEdict(params[1]);
516 return pContext->ThrowNativeError("Edict %d is invalid", params[1]);
519 g_HL2.SetEdictStateChanged(pEdict, params[2]);
524 static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
527 pContext->LocalToString(params[1], &cls);
528 pContext->LocalToString(params[2], &prop);
530 SendProp *pSend = g_HL2.FindInSendTable(cls, prop);
537 return pSend->GetOffset();
540 static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
542 CBaseEntity *pEntity;
544 typedescription_t *td;
546 edict_t *pEdict = GetEntity(params[1], &pEntity);
548 if (!pEdict || !pEntity)
550 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
553 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
555 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
558 pContext->LocalToString(params[2], &offset);
559 if ((td=g_HL2.FindInDataMap(pMap, offset)) == NULL)
564 return td->fieldOffset[TD_OFFSET_NORMAL];
567 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
569 CBaseEntity *pEntity;
570 edict_t *pEdict = GetEntity(params[1], &pEntity);
572 if (!pEdict || !pEntity)
574 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
577 int offset = params[2];
578 if (offset < 0 || offset > 32768)
580 return pContext->ThrowNativeError("Offset %d is invalid", offset);
584 char *src = (char *)((uint8_t *)pEntity + offset);
585 pContext->StringToLocalUTF8(params[3], params[4], src, &len);
590 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
592 CBaseEntity *pEntity;
593 edict_t *pEdict = GetEntity(params[1], &pEntity);
595 if (!pEdict || !pEntity)
597 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
600 int offset = params[2];
601 if (offset < 0 || offset > 32768)
603 return pContext->ThrowNativeError("Offset %d is invalid", offset);
607 char *dest = (char *)((uint8_t *)pEntity + offset);
609 pContext->LocalToString(params[3], &src);
610 size_t len = strncopy(dest, src, params[4]);
614 g_HL2.SetEdictStateChanged(pEdict, offset);
620 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
622 CBaseEntity *pEntity;
625 edict_t *pEdict = GetEntity(params[1], &pEntity);
627 if (!pEdict || !pEntity)
629 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
637 typedescription_t *td;
638 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
640 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
642 pContext->LocalToString(params[3], &prop);
643 if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
645 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
647 if (td->fieldType != FIELD_CHARACTER)
649 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
651 offset = td->fieldOffset[TD_OFFSET_NORMAL];
657 IServerNetworkable *pNet = pEdict->GetNetworkable();
660 return pContext->ThrowNativeError("The edict is not networkable");
662 pContext->LocalToString(params[3], &prop);
663 SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
666 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
668 if (pSend->GetType() != DPT_String)
670 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
672 offset = pSend->GetOffset();
677 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
682 char *src = (char *)((uint8_t *)pEntity + offset);
683 pContext->StringToLocalUTF8(params[4], params[5], src, &len);
688 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
690 CBaseEntity *pEntity;
694 bool is_sendprop = false;
695 edict_t *pEdict = GetEntity(params[1], &pEntity);
697 if (!pEdict || !pEntity)
699 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
707 typedescription_t *td;
708 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
710 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
712 pContext->LocalToString(params[3], &prop);
713 if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
715 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
717 if (td->fieldType != FIELD_CHARACTER)
719 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
721 offset = td->fieldOffset[TD_OFFSET_NORMAL];
722 maxlen = td->fieldSize;
728 IServerNetworkable *pNet = pEdict->GetNetworkable();
731 return pContext->ThrowNativeError("The edict is not networkable");
733 pContext->LocalToString(params[3], &prop);
734 SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
737 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
739 if (pSend->GetType() != DPT_String)
741 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
743 offset = pSend->GetOffset();
744 maxlen = DT_MAX_STRING_BUFFERSIZE;
750 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
755 char *dest = (char *)((uint8_t *)pEntity + offset);
757 pContext->LocalToString(params[4], &src);
758 size_t len = strncopy(dest, src, maxlen);
762 g_HL2.SetEdictStateChanged(pEdict, offset);
768 REGISTER_NATIVES(entityNatives)
770 {"ChangeEdictState", ChangeEdictState},
771 {"CreateEdict", CreateEdict},
772 {"FindSendPropOffs", FindSendPropOffs},
773 {"GetEdictClassname", GetEdictClassname},
774 {"GetEdictFlags", GetEdictFlags},
775 {"GetEntData", GetEntData},
776 {"GetEntDataEnt", GetEntDataEnt},
777 {"GetEntDataFloat", GetEntDataFloat},
778 {"GetEntDataVector", GetEntDataVector},
779 {"GetEntityCount", GetEntityCount},
780 {"GetEntityNetClass", GetEntityNetClass},
781 {"GetMaxEntities", GetMaxEntities},
782 {"IsEntNetworkable", IsEntNetworkable},
783 {"IsValidEdict", IsValidEdict},
784 {"IsValidEntity", IsValidEntity},
785 {"RemoveEdict", RemoveEdict},
786 {"SetEdictFlags", SetEdictFlags},
787 {"SetEntData", SetEntData},
788 {"SetEntDataEnt", SetEntDataEnt},
789 {"SetEntDataFloat", SetEntDataFloat},
790 {"SetEntDataVector", SetEntDataVector},
791 {"FindDataMapOffs", FindDataMapOffs},
792 {"GetEntDataString", GetEntDataString},
793 {"SetEntDataString", SetEntDataString},
794 {"GetEntPropString", GetEntPropString},
795 {"SetEntPropString", SetEntPropString},