3 * =============================================================================
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 "sm_globals.h"
33 #include "sourcemod.h"
34 #include "sourcemm_api.h"
35 #include "PlayerManager.h"
36 #include "HalfLife2.h"
37 #include "GameConfigs.h"
38 #include "sm_stringutil.h"
48 PropField_Unsupported, /**< The type is unsupported. */
49 PropField_Integer, /**< Valid for SendProp and Data fields */
50 PropField_Float, /**< Valid for SendProp and Data fields */
51 PropField_Entity, /**< Valid for Data fields only (SendProp shows as int) */
52 PropField_Vector, /**< Valid for SendProp and Data fields */
53 PropField_String, /**< Valid for SendProp and Data fields */
54 PropField_String_T, /**< Valid for Data fields. Read only! */
57 inline edict_t *BaseEntityToEdict(CBaseEntity *pEntity)
59 IServerUnknown *pUnk = (IServerUnknown *)pEntity;
60 IServerNetworkable *pNet = pUnk->GetNetworkable();
67 return pNet->GetEdict();
70 inline edict_t *GetEdict(cell_t num)
72 CBaseEntity *pEntity = g_HL2.ReferenceToEntity(num);
79 edict_t *pEdict = ::BaseEntityToEdict(pEntity);
80 if (!pEdict || pEdict->IsFree())
85 int index = g_HL2.ReferenceToIndex(num);
86 if (index > 0 && index <= g_Players.GetMaxClients())
88 CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
89 if (!pPlayer || !pPlayer->IsConnected())
98 edict_t *GetEntity(cell_t num, CBaseEntity **pData)
100 CBaseEntity *pEntity = g_HL2.ReferenceToEntity(num);
107 int index = g_HL2.ReferenceToIndex(num);
108 if (index > 0 && index <= g_Players.GetMaxClients())
110 CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
111 if (!pPlayer || !pPlayer->IsConnected())
119 edict_t *pEdict = ::BaseEntityToEdict(pEntity);
120 if (!pEdict || pEdict->IsFree())
128 class VEmptyClass {};
129 datamap_t *VGetDataDescMap(CBaseEntity *pThisPtr, int offset)
131 void **this_ptr = *reinterpret_cast<void ***>(&pThisPtr);
132 void **vtable = *reinterpret_cast<void ***>(pThisPtr);
133 void *vfunc = vtable[offset];
137 datamap_t *(VEmptyClass::*mfpnew)();
138 #ifndef PLATFORM_POSIX
153 return (datamap_t *)(reinterpret_cast<VEmptyClass *>(this_ptr)->*u.mfpnew)();
156 inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity)
160 if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset)
165 return VGetDataDescMap(pEntity, offset);
168 /* :TODO: Move this! */
169 datamap_t *CHalfLife2::GetDataMap(CBaseEntity *pEntity)
171 return CBaseEntity_GetDataDescMap(pEntity);
174 static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params)
176 return gpGlobals->maxEntities;
179 static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params)
181 edict_t *pEdict = engine->CreateEdict();
188 return IndexOfEdict(pEdict);
191 static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
193 edict_t *pEdict = GetEdict(params[1]);
197 return pContext->ThrowNativeError("Edict %d (%d) is not a valid edict", g_HL2.ReferenceToIndex(params[1]), params[1]);
200 engine->RemoveEdict(pEdict);
205 static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params)
207 edict_t *pEdict = GetEdict(params[1]);
214 /* Shouldn't be necessary... not sure though */
215 return pEdict->IsFree() ? 0 : 1;
218 static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
220 CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
222 return (pEntity != NULL) ? 1 : 0;
225 static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
227 edict_t *pEdict = GetEdict(params[1]);
234 return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
237 static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
239 return engine->GetEntityCount();
242 static cell_t GetEdictFlags(IPluginContext *pContext, const cell_t *params)
244 edict_t *pEdict = GetEdict(params[1]);
248 return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
251 return pEdict->m_fStateFlags;
254 static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params)
256 edict_t *pEdict = GetEdict(params[1]);
260 return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
263 pEdict->m_fStateFlags = params[2];
268 static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params)
270 edict_t *pEdict = GetEdict(params[1]);
274 return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
277 const char *cls = pEdict->GetClassName();
279 if (!cls || cls[0] == '\0')
284 pContext->StringToLocal(params[2], params[3], cls);
289 static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
291 CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
293 IServerUnknown *pUnk = (IServerUnknown *)pEntity;
297 return pContext->ThrowNativeError("Invalid entity (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
300 IServerNetworkable *pNet = pUnk->GetNetworkable();
306 ServerClass *pClass = pNet->GetServerClass();
308 pContext->StringToLocal(params[2], params[3], pClass->GetName());
313 static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
315 CBaseEntity *pEntity;
316 GetEntity(params[1], &pEntity);
320 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
323 int offset = params[2];
324 if (offset <= 0 || offset > 32768)
326 return pContext->ThrowNativeError("Offset %d is invalid", offset);
332 return *(int *)((uint8_t *)pEntity + offset);
334 return *(short *)((uint8_t *)pEntity + offset);
336 return *((uint8_t *)pEntity + offset);
338 return pContext->ThrowNativeError("Integer size %d is invalid", params[3]);
342 static cell_t SetEntData(IPluginContext *pContext, const cell_t *params)
344 CBaseEntity *pEntity;
345 edict_t *pEdict = GetEntity(params[1], &pEntity);
349 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
352 int offset = params[2];
353 if (offset <= 0 || offset > 32768)
355 return pContext->ThrowNativeError("Offset %d is invalid", offset);
358 if (params[5] && (pEdict != NULL))
360 g_HL2.SetEdictStateChanged(pEdict, offset);
367 *(int *)((uint8_t *)pEntity + offset) = params[3];
372 *(short *)((uint8_t *)pEntity + offset) = params[3];
377 *((uint8_t *)pEntity + offset) = params[3];
381 return pContext->ThrowNativeError("Integer size %d is invalid", params[4]);
387 static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
389 CBaseEntity *pEntity;
390 GetEntity(params[1], &pEntity);
394 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
397 int offset = params[2];
398 if (offset <= 0 || offset > 32768)
400 return pContext->ThrowNativeError("Offset %d is invalid", offset);
403 float f = *(float *)((uint8_t *)pEntity + offset);
408 static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params)
410 CBaseEntity *pEntity;
411 edict_t *pEdict = GetEntity(params[1], &pEntity);
415 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
418 int offset = params[2];
419 if (offset <= 0 || offset > 32768)
421 return pContext->ThrowNativeError("Offset %d is invalid", offset);
424 *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
426 if (params[4] && (pEdict != NULL))
428 g_HL2.SetEdictStateChanged(pEdict, offset);
434 static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
436 CBaseEntity *pEntity;
437 GetEntity(params[1], &pEntity);
441 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), 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 vec[0] = sp_ftoc(v->x);
456 vec[1] = sp_ftoc(v->y);
457 vec[2] = sp_ftoc(v->z);
462 static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params)
464 CBaseEntity *pEntity;
465 edict_t *pEdict = GetEntity(params[1], &pEntity);
469 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
472 int offset = params[2];
473 if (offset <= 0 || offset > 32768)
475 return pContext->ThrowNativeError("Offset %d is invalid", offset);
478 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
481 pContext->LocalToPhysAddr(params[3], &vec);
483 v->x = sp_ctof(vec[0]);
484 v->y = sp_ctof(vec[1]);
485 v->z = sp_ctof(vec[2]);
487 if (params[4] && (pEdict != NULL))
489 g_HL2.SetEdictStateChanged(pEdict, offset);
495 /* THIS GUY IS DEPRECATED. */
496 static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
498 CBaseEntity *pEntity;
499 GetEntity(params[1], &pEntity);
503 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
506 int offset = params[2];
507 if (offset <= 0 || offset > 32768)
509 return pContext->ThrowNativeError("Offset %d is invalid", offset);
512 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
519 int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
520 return g_HL2.ReferenceToBCompatRef(ref);
523 int CheckBaseHandle(CBaseHandle &hndl)
530 int index = hndl.GetEntryIndex();
532 edict_t *pStoredEdict;
533 CBaseEntity *pStoredEntity;
535 pStoredEdict = GetEntity(index, &pStoredEntity);
537 if (pStoredEdict == NULL || pStoredEntity == NULL)
542 IServerEntity *pSE = pStoredEdict->GetIServerEntity();
549 if (pSE->GetRefEHandle() != hndl)
557 static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
559 CBaseEntity *pEntity;
560 GetEntity(params[1], &pEntity);
564 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
567 int offset = params[2];
568 if (offset <= 0 || offset > 32768)
570 return pContext->ThrowNativeError("Offset %d is invalid", offset);
573 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
575 int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
576 return g_HL2.ReferenceToBCompatRef(ref);
579 /* THIS GUY IS DEPRECATED. */
580 static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
582 CBaseEntity *pEntity;
583 edict_t *pEdict = GetEntity(params[1], &pEntity);
587 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
590 int offset = params[2];
591 if (offset <= 0 || offset > 32768)
593 return pContext->ThrowNativeError("Offset %d is invalid", offset);
596 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
598 if (params[3] == 0 || params[3] == INVALID_EHANDLE_INDEX)
603 GetEntity(params[3], &pOther);
607 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[3]), params[3]);
610 IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
611 hndl.Set(pHandleEnt);
614 if (params[4] && (pEdict != NULL))
616 g_HL2.SetEdictStateChanged(pEdict, offset);
622 static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
624 CBaseEntity *pEntity;
625 edict_t *pEdict = GetEntity(params[1], &pEntity);
629 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
632 int offset = params[2];
633 if (offset <= 0 || offset > 32768)
635 return pContext->ThrowNativeError("Offset %d is invalid", offset);
638 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
640 if (params[3] == INVALID_EHANDLE_INDEX)
647 GetEntity(params[3], &pOther);
651 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[3]), params[3]);
654 IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
655 hndl.Set(pHandleEnt);
658 if (params[4] && (pEdict != NULL))
660 g_HL2.SetEdictStateChanged(pEdict, offset);
666 static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
668 edict_t *pEdict = GetEdict(params[1]);
672 return pContext->ThrowNativeError("Edict %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
675 g_HL2.SetEdictStateChanged(pEdict, params[2]);
680 static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
683 pContext->LocalToString(params[1], &cls);
684 pContext->LocalToString(params[2], &prop);
686 SendProp *pSend = g_HL2.FindInSendTable(cls, prop);
693 return pSend->GetOffset();
696 static cell_t FindSendPropInfo(IPluginContext *pContext, const cell_t *params)
699 sm_sendprop_info_t info;
700 cell_t *pType, *pBits, *pLocal;
702 pContext->LocalToString(params[1], &cls);
703 pContext->LocalToString(params[2], &prop);
705 if (!g_HL2.FindSendPropInfo(cls, prop, &info))
710 pContext->LocalToPhysAddr(params[3], &pType);
711 pContext->LocalToPhysAddr(params[4], &pBits);
712 pContext->LocalToPhysAddr(params[5], &pLocal);
714 switch (info.prop->GetType())
718 *pType = PropField_Integer;
723 *pType = PropField_Float;
728 *pType = PropField_String;
733 *pType = PropField_Vector;
738 *pType = PropField_Unsupported;
743 *pBits = info.prop->m_nBits;
744 *pLocal = info.prop->GetOffset();
746 return info.actual_offset;
749 static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
751 CBaseEntity *pEntity;
753 typedescription_t *td;
755 GetEntity(params[1], &pEntity);
759 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
762 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
764 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
767 pContext->LocalToString(params[2], &offset);
768 if ((td=g_HL2.FindInDataMap(pMap, offset)) == NULL)
775 cell_t *pType, *pSize;
777 pContext->LocalToPhysAddr(params[3], &pType);
778 pContext->LocalToPhysAddr(params[4], &pSize);
780 switch (td->fieldType)
783 case FIELD_MODELINDEX:
784 case FIELD_MATERIALINDEX:
788 *pType = PropField_Integer;
793 case FIELD_POSITION_VECTOR:
795 *pType = PropField_Vector;
801 *pType = PropField_Integer;
807 *pType = PropField_Integer;
811 case FIELD_CHARACTER:
813 if (td->fieldSize == 1)
815 *pType = PropField_Integer;
820 *pType = PropField_String;
821 *pSize = 8 * td->fieldSize;
825 case FIELD_MODELNAME:
826 case FIELD_SOUNDNAME:
829 *pSize = sizeof(string_t);
830 *pType = PropField_String_T;
836 *pType = PropField_Float;
842 *pType = PropField_Entity;
848 *pType = PropField_Unsupported;
854 return td->fieldOffset[TD_OFFSET_NORMAL];
857 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
859 CBaseEntity *pEntity;
860 GetEntity(params[1], &pEntity);
864 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
867 int offset = params[2];
868 if (offset < 0 || offset > 32768)
870 return pContext->ThrowNativeError("Offset %d is invalid", offset);
874 char *src = (char *)((uint8_t *)pEntity + offset);
875 pContext->StringToLocalUTF8(params[3], params[4], src, &len);
880 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
882 CBaseEntity *pEntity;
883 edict_t *pEdict = GetEntity(params[1], &pEntity);
887 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
890 int offset = params[2];
891 if (offset < 0 || offset > 32768)
893 return pContext->ThrowNativeError("Offset %d is invalid", offset);
897 char *dest = (char *)((uint8_t *)pEntity + offset);
899 pContext->LocalToString(params[3], &src);
900 size_t len = strncopy(dest, src, params[4]);
902 if (params[5] && (pEdict != NULL))
904 g_HL2.SetEdictStateChanged(pEdict, offset);
910 #define FIND_PROP_DATA(td) \
912 if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL) \
914 return pContext->ThrowNativeError("Could not retrieve datamap"); \
916 if ((td = g_HL2.FindInDataMap(pMap, prop)) == NULL) \
918 return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
924 #define FIND_PROP_SEND(pProp) \
925 IServerUnknown *pUnk = (IServerUnknown *)pEntity; \
926 IServerNetworkable *pNet = pUnk->GetNetworkable(); \
929 return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); \
931 if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, pProp)) \
933 return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
939 inline int MatchFieldAsInteger(int field_type)
944 case FIELD_MODELINDEX:
945 case FIELD_MATERIALINDEX:
951 case FIELD_CHARACTER:
962 static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
964 CBaseEntity *pEntity;
967 const char *class_name;
971 pEdict = GetEntity(params[1], &pEntity);
975 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
978 /* TODO: Find a way to lookup classname without having an edict - Is this a guaranteed prop? */
979 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
984 pContext->LocalToString(params[3], &prop);
990 typedescription_t *td;
994 if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
996 return pContext->ThrowNativeError("Data field %s is not an integer (%d)",
1001 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1006 sm_sendprop_info_t info;
1008 FIND_PROP_SEND(&info);
1010 if (info.prop->GetType() != DPT_Int)
1012 return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
1014 info.prop->GetType(),
1019 bit_count = info.prop->m_nBits;
1020 offset = info.actual_offset;
1025 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1031 bit_count = params[4] * 8;
1034 if (bit_count >= 17)
1036 return *(int32_t *)((uint8_t *)pEntity + offset);
1038 else if (bit_count >= 9)
1040 return *(int16_t *)((uint8_t *)pEntity + offset);
1042 else if (bit_count >= 2)
1044 return *(int8_t *)((uint8_t *)pEntity + offset);
1048 return *(bool *)((uint8_t *)pEntity + offset) ? 1 : 0;
1054 static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
1056 CBaseEntity *pEntity;
1059 const char *class_name;
1063 pEdict = GetEntity(params[1], &pEntity);
1067 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1070 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1075 pContext->LocalToString(params[3], &prop);
1081 typedescription_t *td;
1085 if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
1087 return pContext->ThrowNativeError("Data field %s is not an integer (%d)",
1092 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1097 sm_sendprop_info_t info;
1099 FIND_PROP_SEND(&info);
1101 if (info.prop->GetType() != DPT_Int)
1103 return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
1105 info.prop->GetType(),
1110 bit_count = info.prop->m_nBits;
1111 offset = info.actual_offset;
1116 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1122 bit_count = params[5] * 8;
1125 if (bit_count >= 17)
1127 *(int32_t *)((uint8_t *)pEntity + offset) = params[4];
1129 else if (bit_count >= 9)
1131 *(int16_t *)((uint8_t *)pEntity + offset) = (int16_t)params[4];
1133 else if (bit_count >= 2)
1135 *(int8_t *)((uint8_t *)pEntity + offset) = (int8_t)params[4];
1139 *(bool *)((uint8_t *)pEntity + offset) = params[4] ? true : false;
1145 static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params)
1147 CBaseEntity *pEntity;
1150 const char *class_name;
1153 pEdict = GetEntity(params[1], &pEntity);
1157 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1160 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1165 pContext->LocalToString(params[3], &prop);
1171 typedescription_t *td;
1175 if (td->fieldType != FIELD_FLOAT
1176 && td->fieldType != FIELD_TIME)
1178 return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])",
1185 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1190 sm_sendprop_info_t info;
1192 FIND_PROP_SEND(&info);
1194 if (info.prop->GetType() != DPT_Float)
1196 return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
1198 info.prop->GetType(),
1202 offset = info.actual_offset;
1207 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1211 float val = *(float *)((uint8_t *)pEntity + offset);
1213 return sp_ftoc(val);
1216 static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params)
1218 CBaseEntity *pEntity;
1221 const char *class_name;
1224 pEdict = GetEntity(params[1], &pEntity);
1228 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1231 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1236 pContext->LocalToString(params[3], &prop);
1242 typedescription_t *td;
1246 if (td->fieldType != FIELD_FLOAT
1247 && td->fieldType != FIELD_TIME)
1249 return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])",
1256 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1261 sm_sendprop_info_t info;
1263 FIND_PROP_SEND(&info);
1265 if (info.prop->GetType() != DPT_Float)
1267 return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
1269 info.prop->GetType(),
1273 offset = info.actual_offset;
1278 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1282 *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[4]);
1284 if (params[2] == Prop_Send && (pEdict != NULL))
1286 g_HL2.SetEdictStateChanged(pEdict, offset);
1292 static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params)
1294 CBaseEntity *pEntity;
1297 const char *class_name;
1300 pEdict = GetEntity(params[1], &pEntity);
1304 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1307 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1312 pContext->LocalToString(params[3], &prop);
1318 typedescription_t *td;
1322 if (td->fieldType != FIELD_EHANDLE)
1324 return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)",
1330 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1335 sm_sendprop_info_t info;
1337 FIND_PROP_SEND(&info);
1339 if (info.prop->GetType() != DPT_Int)
1341 return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
1343 info.prop->GetType(),
1347 offset = info.actual_offset;
1352 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1356 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
1358 int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
1359 return g_HL2.ReferenceToBCompatRef(ref);
1362 static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
1364 CBaseEntity *pEntity;
1367 const char *class_name;
1370 pEdict = GetEntity(params[1], &pEntity);
1374 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1377 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1382 pContext->LocalToString(params[3], &prop);
1388 typedescription_t *td;
1392 if (td->fieldType != FIELD_EHANDLE)
1394 return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)",
1400 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1405 sm_sendprop_info_t info;
1407 FIND_PROP_SEND(&info);
1409 if (info.prop->GetType() != DPT_Int)
1411 return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
1413 info.prop->GetType(),
1417 offset = info.actual_offset;
1422 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1426 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
1428 if (params[4] == -1)
1434 CBaseEntity *pOther;
1435 GetEntity(params[4], &pOther);
1439 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[4]), params[4]);
1442 IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
1443 hndl.Set(pHandleEnt);
1446 if (params[2] == Prop_Send && (pEdict != NULL))
1448 g_HL2.SetEdictStateChanged(pEdict, offset);
1454 static cell_t GetEntPropVector(IPluginContext *pContext, const cell_t *params)
1456 CBaseEntity *pEntity;
1459 const char *class_name;
1462 pEdict = GetEntity(params[1], &pEntity);
1466 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1469 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1474 pContext->LocalToString(params[3], &prop);
1480 typedescription_t *td;
1484 if (td->fieldType != FIELD_VECTOR
1485 && td->fieldType != FIELD_POSITION_VECTOR)
1487 return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])",
1491 FIELD_POSITION_VECTOR);
1494 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1499 sm_sendprop_info_t info;
1501 FIND_PROP_SEND(&info);
1503 if (info.prop->GetType() != DPT_Vector)
1505 return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
1507 info.prop->GetType(),
1511 offset = info.actual_offset;
1516 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1520 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
1523 pContext->LocalToPhysAddr(params[4], &vec);
1525 vec[0] = sp_ftoc(v->x);
1526 vec[1] = sp_ftoc(v->y);
1527 vec[2] = sp_ftoc(v->z);
1532 static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params)
1534 CBaseEntity *pEntity;
1537 const char *class_name;
1540 pEdict = GetEntity(params[1], &pEntity);
1544 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1547 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1552 pContext->LocalToString(params[3], &prop);
1558 typedescription_t *td;
1562 if (td->fieldType != FIELD_VECTOR
1563 && td->fieldType != FIELD_POSITION_VECTOR)
1565 return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])",
1569 FIELD_POSITION_VECTOR);
1572 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1577 sm_sendprop_info_t info;
1579 FIND_PROP_SEND(&info);
1581 if (info.prop->GetType() != DPT_Vector)
1583 return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
1585 info.prop->GetType(),
1589 offset = info.actual_offset;
1594 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1598 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
1601 pContext->LocalToPhysAddr(params[4], &vec);
1603 v->x = sp_ctof(vec[0]);
1604 v->y = sp_ctof(vec[1]);
1605 v->z = sp_ctof(vec[2]);
1607 if (params[2] == Prop_Send && (pEdict != NULL))
1609 g_HL2.SetEdictStateChanged(pEdict, offset);
1615 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
1617 CBaseEntity *pEntity;
1620 const char *class_name;
1622 bool bIsStringIndex;
1624 pEdict = GetEntity(params[1], &pEntity);
1628 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1631 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1636 pContext->LocalToString(params[3], &prop);
1638 bIsStringIndex = false;
1644 typedescription_t *td;
1648 if (td->fieldType != FIELD_CHARACTER
1649 && td->fieldType != FIELD_STRING
1650 && td->fieldType != FIELD_MODELNAME
1651 && td->fieldType != FIELD_SOUNDNAME)
1653 return pContext->ThrowNativeError("Data field %s is not a string (%d != %d)",
1659 bIsStringIndex = (td->fieldType != FIELD_CHARACTER);
1661 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1666 sm_sendprop_info_t info;
1668 FIND_PROP_SEND(&info);
1670 if (info.prop->GetType() != DPT_String)
1672 return pContext->ThrowNativeError("SendProp %s is not a string (%d != %d)",
1674 info.prop->GetType(),
1678 offset = info.actual_offset;
1684 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1691 if (!bIsStringIndex)
1693 src = (char *)((uint8_t *)pEntity + offset);
1699 idx = *(string_t *)((uint8_t *)pEntity + offset);
1700 src = (idx == NULL_STRING) ? "" : STRING(idx);
1703 pContext->StringToLocalUTF8(params[4], params[5], src, &len);
1708 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
1710 CBaseEntity *pEntity;
1714 edict_t *pEdict = GetEntity(params[1], &pEntity);
1718 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1726 typedescription_t *td;
1727 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
1729 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
1731 pContext->LocalToString(params[3], &prop);
1732 if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
1734 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
1736 if (td->fieldType != FIELD_CHARACTER)
1738 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
1740 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1741 maxlen = td->fieldSize;
1747 IServerUnknown *pUnk = (IServerUnknown *)pEntity;
1748 IServerNetworkable *pNet = pUnk->GetNetworkable();
1751 return pContext->ThrowNativeError("The edict is not networkable");
1753 pContext->LocalToString(params[3], &prop);
1754 SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
1757 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
1759 if (pSend->GetType() != DPT_String)
1761 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
1763 offset = pSend->GetOffset();
1764 maxlen = DT_MAX_STRING_BUFFERSIZE;
1769 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1774 char *dest = (char *)((uint8_t *)pEntity + offset);
1776 pContext->LocalToString(params[4], &src);
1777 size_t len = strncopy(dest, src, maxlen);
1779 if (params[2] == Prop_Send && (pEdict != NULL))
1781 g_HL2.SetEdictStateChanged(pEdict, offset);
1787 REGISTER_NATIVES(entityNatives)
1789 {"ChangeEdictState", ChangeEdictState},
1790 {"CreateEdict", CreateEdict},
1791 {"FindDataMapOffs", FindDataMapOffs},
1792 {"FindSendPropInfo", FindSendPropInfo},
1793 {"FindSendPropOffs", FindSendPropOffs},
1794 {"GetEdictClassname", GetEdictClassname},
1795 {"GetEdictFlags", GetEdictFlags},
1796 {"GetEntData", GetEntData},
1797 {"GetEntDataEnt", GetEntDataEnt}, /** DEPRECATED */
1798 {"GetEntDataEnt2", GetEntDataEnt2},
1799 {"GetEntDataFloat", GetEntDataFloat},
1800 {"GetEntDataString", GetEntDataString},
1801 {"GetEntDataVector", GetEntDataVector},
1802 {"GetEntProp", GetEntProp},
1803 {"GetEntPropEnt", GetEntPropEnt},
1804 {"GetEntPropFloat", GetEntPropFloat},
1805 {"GetEntPropString", GetEntPropString},
1806 {"GetEntPropVector", GetEntPropVector},
1807 {"GetEntityCount", GetEntityCount},
1808 {"GetEntityNetClass", GetEntityNetClass},
1809 {"GetMaxEntities", GetMaxEntities},
1810 {"IsEntNetworkable", IsEntNetworkable},
1811 {"IsValidEdict", IsValidEdict},
1812 {"IsValidEntity", IsValidEntity},
1813 {"RemoveEdict", RemoveEdict},
1814 {"SetEdictFlags", SetEdictFlags},
1815 {"SetEntData", SetEntData},
1816 {"SetEntDataEnt", SetEntDataEnt}, /** DEPRECATED */
1817 {"SetEntDataEnt2", SetEntDataEnt2},
1818 {"SetEntDataFloat", SetEntDataFloat},
1819 {"SetEntDataVector", SetEntDataVector},
1820 {"SetEntDataString", SetEntDataString},
1821 {"SetEntProp", SetEntProp},
1822 {"SetEntPropEnt", SetEntPropEnt},
1823 {"SetEntPropFloat", SetEntPropFloat},
1824 {"SetEntPropString", SetEntPropString},
1825 {"SetEntPropVector", SetEntPropVector},