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)
73 if (!IndexToAThings(num, NULL, &pEdict))
81 inline CBaseEntity *GetEntity(cell_t num)
84 if (!IndexToAThings(num, &pEntity, NULL))
92 /* Given an entity reference or index, fill out a CBaseEntity and/or edict.
93 If lookup is successful, returns true and writes back the two parameters.
94 If lookup fails, returns false and doesn't touch the params. */
95 bool IndexToAThings(cell_t num, CBaseEntity **pEntData, edict_t **pEdictData)
97 CBaseEntity *pEntity = g_HL2.ReferenceToEntity(num);
104 int index = g_HL2.ReferenceToIndex(num);
105 if (index > 0 && index <= g_Players.GetMaxClients())
107 CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
108 if (!pPlayer || !pPlayer->IsConnected())
121 edict_t *pEdict = ::BaseEntityToEdict(pEntity);
122 if (pEdict->IsFree())
127 *pEdictData = pEdict;
133 <predcrab> AThings is like guaranteed r+ by dvander though
134 <predcrab> he wont even read the rest of the patch to nit stuff
135 <Fyren> Like I wasn't going to r? you anyway!
136 <predcrab> he still sees!
137 <predcrab> he's everywhere
140 class VEmptyClass {};
141 datamap_t *VGetDataDescMap(CBaseEntity *pThisPtr, int offset)
143 void **this_ptr = *reinterpret_cast<void ***>(&pThisPtr);
144 void **vtable = *reinterpret_cast<void ***>(pThisPtr);
145 void *vfunc = vtable[offset];
149 datamap_t *(VEmptyClass::*mfpnew)();
150 #ifndef PLATFORM_POSIX
165 return (datamap_t *)(reinterpret_cast<VEmptyClass *>(this_ptr)->*u.mfpnew)();
168 inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity)
172 if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset)
177 return VGetDataDescMap(pEntity, offset);
180 /* :TODO: Move this! */
181 datamap_t *CHalfLife2::GetDataMap(CBaseEntity *pEntity)
183 return CBaseEntity_GetDataDescMap(pEntity);
186 static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params)
188 return gpGlobals->maxEntities;
191 static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params)
193 edict_t *pEdict = engine->CreateEdict();
200 return IndexOfEdict(pEdict);
203 static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
205 edict_t *pEdict = GetEdict(params[1]);
209 return pContext->ThrowNativeError("Edict %d (%d) is not a valid edict", g_HL2.ReferenceToIndex(params[1]), params[1]);
212 engine->RemoveEdict(pEdict);
217 static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params)
219 edict_t *pEdict = GetEdict(params[1]);
226 /* Shouldn't be necessary... not sure though */
227 return pEdict->IsFree() ? 0 : 1;
230 static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
232 CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
234 return (pEntity != NULL) ? 1 : 0;
237 static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
239 edict_t *pEdict = GetEdict(params[1]);
246 return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
249 static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
251 return engine->GetEntityCount();
254 static cell_t GetEdictFlags(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 return pEdict->m_fStateFlags;
266 static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params)
268 edict_t *pEdict = GetEdict(params[1]);
272 return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
275 pEdict->m_fStateFlags = params[2];
280 static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params)
282 edict_t *pEdict = GetEdict(params[1]);
286 return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
289 const char *cls = pEdict->GetClassName();
291 if (!cls || cls[0] == '\0')
296 pContext->StringToLocal(params[2], params[3], cls);
301 static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
303 CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
305 IServerUnknown *pUnk = (IServerUnknown *)pEntity;
309 return pContext->ThrowNativeError("Invalid entity (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
312 IServerNetworkable *pNet = pUnk->GetNetworkable();
318 ServerClass *pClass = pNet->GetServerClass();
320 pContext->StringToLocal(params[2], params[3], pClass->GetName());
325 static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
327 CBaseEntity *pEntity = GetEntity(params[1]);
331 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
334 int offset = params[2];
335 if (offset <= 0 || offset > 32768)
337 return pContext->ThrowNativeError("Offset %d is invalid", offset);
343 return *(int *)((uint8_t *)pEntity + offset);
345 return *(short *)((uint8_t *)pEntity + offset);
347 return *((uint8_t *)pEntity + offset);
349 return pContext->ThrowNativeError("Integer size %d is invalid", params[3]);
353 static cell_t SetEntData(IPluginContext *pContext, const cell_t *params)
355 CBaseEntity *pEntity;
358 if (!IndexToAThings(params[1], &pEntity, &pEdict))
360 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
363 int offset = params[2];
364 if (offset <= 0 || offset > 32768)
366 return pContext->ThrowNativeError("Offset %d is invalid", offset);
369 if (params[5] && (pEdict != NULL))
371 g_HL2.SetEdictStateChanged(pEdict, offset);
378 *(int *)((uint8_t *)pEntity + offset) = params[3];
383 *(short *)((uint8_t *)pEntity + offset) = params[3];
388 *((uint8_t *)pEntity + offset) = params[3];
392 return pContext->ThrowNativeError("Integer size %d is invalid", params[4]);
398 static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
400 CBaseEntity *pEntity = GetEntity(params[1]);
404 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
407 int offset = params[2];
408 if (offset <= 0 || offset > 32768)
410 return pContext->ThrowNativeError("Offset %d is invalid", offset);
413 float f = *(float *)((uint8_t *)pEntity + offset);
418 static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params)
420 CBaseEntity *pEntity;
423 if (!IndexToAThings(params[1], &pEntity, &pEdict))
425 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
428 int offset = params[2];
429 if (offset <= 0 || offset > 32768)
431 return pContext->ThrowNativeError("Offset %d is invalid", offset);
434 *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
436 if (params[4] && (pEdict != NULL))
438 g_HL2.SetEdictStateChanged(pEdict, offset);
444 static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
446 CBaseEntity *pEntity = GetEntity(params[1]);
450 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
453 int offset = params[2];
454 if (offset <= 0 || offset > 32768)
456 return pContext->ThrowNativeError("Offset %d is invalid", offset);
459 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
462 pContext->LocalToPhysAddr(params[3], &vec);
464 vec[0] = sp_ftoc(v->x);
465 vec[1] = sp_ftoc(v->y);
466 vec[2] = sp_ftoc(v->z);
471 static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params)
473 CBaseEntity *pEntity;
476 if (!IndexToAThings(params[1], &pEntity, &pEdict))
478 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
481 int offset = params[2];
482 if (offset <= 0 || offset > 32768)
484 return pContext->ThrowNativeError("Offset %d is invalid", offset);
487 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
490 pContext->LocalToPhysAddr(params[3], &vec);
492 v->x = sp_ctof(vec[0]);
493 v->y = sp_ctof(vec[1]);
494 v->z = sp_ctof(vec[2]);
496 if (params[4] && (pEdict != NULL))
498 g_HL2.SetEdictStateChanged(pEdict, offset);
504 /* THIS GUY IS DEPRECATED. */
505 static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
507 CBaseEntity *pEntity = GetEntity(params[1]);
511 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
514 int offset = params[2];
515 if (offset <= 0 || offset > 32768)
517 return pContext->ThrowNativeError("Offset %d is invalid", offset);
520 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
527 int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
528 return g_HL2.ReferenceToBCompatRef(ref);
531 int CheckBaseHandle(CBaseHandle &hndl)
538 int index = hndl.GetEntryIndex();
540 edict_t *pStoredEdict;
541 CBaseEntity *pStoredEntity;
543 if (!IndexToAThings(index, &pStoredEntity, &pStoredEdict))
548 if (pStoredEdict == NULL || pStoredEntity == NULL)
553 IServerEntity *pSE = pStoredEdict->GetIServerEntity();
560 if (pSE->GetRefEHandle() != hndl)
568 static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
570 CBaseEntity *pEntity = GetEntity(params[1]);
574 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
577 int offset = params[2];
578 if (offset <= 0 || offset > 32768)
580 return pContext->ThrowNativeError("Offset %d is invalid", offset);
583 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
585 int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
586 return g_HL2.ReferenceToBCompatRef(ref);
589 /* THIS GUY IS DEPRECATED. */
590 static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
592 CBaseEntity *pEntity;
595 if (!IndexToAThings(params[1], &pEntity, &pEdict))
597 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
600 int offset = params[2];
601 if (offset <= 0 || offset > 32768)
603 return pContext->ThrowNativeError("Offset %d is invalid", offset);
606 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
608 if (params[3] == 0 || (unsigned)params[3] == INVALID_EHANDLE_INDEX)
612 CBaseEntity *pOther = GetEntity(params[3]);
616 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[3]), params[3]);
619 IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
620 hndl.Set(pHandleEnt);
623 if (params[4] && (pEdict != NULL))
625 g_HL2.SetEdictStateChanged(pEdict, offset);
631 static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
633 CBaseEntity *pEntity;
636 if (!IndexToAThings(params[1], &pEntity, &pEdict))
638 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
641 int offset = params[2];
642 if (offset <= 0 || offset > 32768)
644 return pContext->ThrowNativeError("Offset %d is invalid", offset);
647 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
649 if ((unsigned)params[3] == INVALID_EHANDLE_INDEX)
655 CBaseEntity *pOther = GetEntity(params[3]);
659 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[3]), params[3]);
662 IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
663 hndl.Set(pHandleEnt);
666 if (params[4] && (pEdict != NULL))
668 g_HL2.SetEdictStateChanged(pEdict, offset);
674 static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
676 edict_t *pEdict = GetEdict(params[1]);
680 return pContext->ThrowNativeError("Edict %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
683 g_HL2.SetEdictStateChanged(pEdict, params[2]);
688 static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
691 pContext->LocalToString(params[1], &cls);
692 pContext->LocalToString(params[2], &prop);
694 SendProp *pSend = g_HL2.FindInSendTable(cls, prop);
701 return pSend->GetOffset();
704 static cell_t FindSendPropInfo(IPluginContext *pContext, const cell_t *params)
707 sm_sendprop_info_t info;
708 cell_t *pType, *pBits, *pLocal;
710 pContext->LocalToString(params[1], &cls);
711 pContext->LocalToString(params[2], &prop);
713 if (!g_HL2.FindSendPropInfo(cls, prop, &info))
718 pContext->LocalToPhysAddr(params[3], &pType);
719 pContext->LocalToPhysAddr(params[4], &pBits);
720 pContext->LocalToPhysAddr(params[5], &pLocal);
722 switch (info.prop->GetType())
726 *pType = PropField_Integer;
731 *pType = PropField_Float;
736 *pType = PropField_String;
741 *pType = PropField_Vector;
746 *pType = PropField_Unsupported;
751 *pBits = info.prop->m_nBits;
752 *pLocal = info.prop->GetOffset();
754 return info.actual_offset;
757 static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
759 CBaseEntity *pEntity;
761 typedescription_t *td;
763 pEntity = GetEntity(params[1]);
767 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
770 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
772 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
775 pContext->LocalToString(params[2], &offset);
776 if ((td=g_HL2.FindInDataMap(pMap, offset)) == NULL)
783 cell_t *pType, *pSize;
785 pContext->LocalToPhysAddr(params[3], &pType);
786 pContext->LocalToPhysAddr(params[4], &pSize);
788 switch (td->fieldType)
791 case FIELD_MODELINDEX:
792 case FIELD_MATERIALINDEX:
796 *pType = PropField_Integer;
801 case FIELD_POSITION_VECTOR:
803 *pType = PropField_Vector;
809 *pType = PropField_Integer;
815 *pType = PropField_Integer;
819 case FIELD_CHARACTER:
821 if (td->fieldSize == 1)
823 *pType = PropField_Integer;
828 *pType = PropField_String;
829 *pSize = 8 * td->fieldSize;
833 case FIELD_MODELNAME:
834 case FIELD_SOUNDNAME:
837 *pSize = sizeof(string_t);
838 *pType = PropField_String_T;
844 *pType = PropField_Float;
850 *pType = PropField_Entity;
856 *pType = PropField_Unsupported;
862 return td->fieldOffset[TD_OFFSET_NORMAL];
865 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
867 CBaseEntity *pEntity = GetEntity(params[1]);
871 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
874 int offset = params[2];
875 if (offset < 0 || offset > 32768)
877 return pContext->ThrowNativeError("Offset %d is invalid", offset);
881 char *src = (char *)((uint8_t *)pEntity + offset);
882 pContext->StringToLocalUTF8(params[3], params[4], src, &len);
887 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
889 CBaseEntity *pEntity;
892 if (!IndexToAThings(params[1], &pEntity, &pEdict))
894 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
897 int offset = params[2];
898 if (offset < 0 || offset > 32768)
900 return pContext->ThrowNativeError("Offset %d is invalid", offset);
904 char *dest = (char *)((uint8_t *)pEntity + offset);
906 pContext->LocalToString(params[3], &src);
907 size_t len = strncopy(dest, src, params[4]);
909 if (params[5] && (pEdict != NULL))
911 g_HL2.SetEdictStateChanged(pEdict, offset);
917 #define FIND_PROP_DATA(td) \
919 if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL) \
921 return pContext->ThrowNativeError("Could not retrieve datamap"); \
923 if ((td = g_HL2.FindInDataMap(pMap, prop)) == NULL) \
925 return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
931 #define FIND_PROP_SEND(pProp) \
932 IServerUnknown *pUnk = (IServerUnknown *)pEntity; \
933 IServerNetworkable *pNet = pUnk->GetNetworkable(); \
936 return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); \
938 if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, pProp)) \
940 return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
946 inline int MatchFieldAsInteger(int field_type)
951 case FIELD_MODELINDEX:
952 case FIELD_MATERIALINDEX:
958 case FIELD_CHARACTER:
969 static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
971 CBaseEntity *pEntity;
974 const char *class_name;
978 if (!IndexToAThings(params[1], &pEntity, &pEdict))
980 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
983 /* TODO: Find a way to lookup classname without having an edict - Is this a guaranteed prop? */
984 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
989 pContext->LocalToString(params[3], &prop);
995 typedescription_t *td;
999 if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
1001 return pContext->ThrowNativeError("Data field %s is not an integer (%d)",
1006 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1011 sm_sendprop_info_t info;
1013 FIND_PROP_SEND(&info);
1015 if (info.prop->GetType() != DPT_Int)
1017 return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
1019 info.prop->GetType(),
1024 bit_count = info.prop->m_nBits;
1025 offset = info.actual_offset;
1030 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1036 bit_count = params[4] * 8;
1039 if (bit_count >= 17)
1041 return *(int32_t *)((uint8_t *)pEntity + offset);
1043 else if (bit_count >= 9)
1045 return *(int16_t *)((uint8_t *)pEntity + offset);
1047 else if (bit_count >= 2)
1049 return *(int8_t *)((uint8_t *)pEntity + offset);
1053 return *(bool *)((uint8_t *)pEntity + offset) ? 1 : 0;
1059 static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
1061 CBaseEntity *pEntity;
1064 const char *class_name;
1068 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1070 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1073 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1078 pContext->LocalToString(params[3], &prop);
1084 typedescription_t *td;
1088 if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
1090 return pContext->ThrowNativeError("Data field %s is not an integer (%d)",
1095 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1100 sm_sendprop_info_t info;
1102 FIND_PROP_SEND(&info);
1104 if (info.prop->GetType() != DPT_Int)
1106 return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
1108 info.prop->GetType(),
1113 bit_count = info.prop->m_nBits;
1114 offset = info.actual_offset;
1119 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1125 bit_count = params[5] * 8;
1128 if (bit_count >= 17)
1130 *(int32_t *)((uint8_t *)pEntity + offset) = params[4];
1132 else if (bit_count >= 9)
1134 *(int16_t *)((uint8_t *)pEntity + offset) = (int16_t)params[4];
1136 else if (bit_count >= 2)
1138 *(int8_t *)((uint8_t *)pEntity + offset) = (int8_t)params[4];
1142 *(bool *)((uint8_t *)pEntity + offset) = params[4] ? true : false;
1148 static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params)
1150 CBaseEntity *pEntity;
1153 const char *class_name;
1156 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1158 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1161 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1166 pContext->LocalToString(params[3], &prop);
1172 typedescription_t *td;
1176 if (td->fieldType != FIELD_FLOAT
1177 && td->fieldType != FIELD_TIME)
1179 return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])",
1186 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1191 sm_sendprop_info_t info;
1193 FIND_PROP_SEND(&info);
1195 if (info.prop->GetType() != DPT_Float)
1197 return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
1199 info.prop->GetType(),
1203 offset = info.actual_offset;
1208 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1212 float val = *(float *)((uint8_t *)pEntity + offset);
1214 return sp_ftoc(val);
1217 static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params)
1219 CBaseEntity *pEntity;
1222 const char *class_name;
1225 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1227 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1230 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1235 pContext->LocalToString(params[3], &prop);
1241 typedescription_t *td;
1245 if (td->fieldType != FIELD_FLOAT
1246 && td->fieldType != FIELD_TIME)
1248 return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])",
1255 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1260 sm_sendprop_info_t info;
1262 FIND_PROP_SEND(&info);
1264 if (info.prop->GetType() != DPT_Float)
1266 return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
1268 info.prop->GetType(),
1272 offset = info.actual_offset;
1277 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1281 *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[4]);
1283 if (params[2] == Prop_Send && (pEdict != NULL))
1285 g_HL2.SetEdictStateChanged(pEdict, offset);
1291 static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params)
1293 CBaseEntity *pEntity;
1296 const char *class_name;
1299 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1301 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1304 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1309 pContext->LocalToString(params[3], &prop);
1315 typedescription_t *td;
1319 if (td->fieldType != FIELD_EHANDLE)
1321 return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)",
1327 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1332 sm_sendprop_info_t info;
1334 FIND_PROP_SEND(&info);
1336 if (info.prop->GetType() != DPT_Int)
1338 return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
1340 info.prop->GetType(),
1344 offset = info.actual_offset;
1349 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1353 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
1355 int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
1356 return g_HL2.ReferenceToBCompatRef(ref);
1359 static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
1361 CBaseEntity *pEntity;
1364 const char *class_name;
1367 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1369 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1372 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1377 pContext->LocalToString(params[3], &prop);
1383 typedescription_t *td;
1387 if (td->fieldType != FIELD_EHANDLE)
1389 return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)",
1395 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1400 sm_sendprop_info_t info;
1402 FIND_PROP_SEND(&info);
1404 if (info.prop->GetType() != DPT_Int)
1406 return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
1408 info.prop->GetType(),
1412 offset = info.actual_offset;
1417 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1421 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
1423 if (params[4] == -1)
1429 CBaseEntity *pOther = GetEntity(params[4]);
1433 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[4]), params[4]);
1436 IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
1437 hndl.Set(pHandleEnt);
1440 if (params[2] == Prop_Send && (pEdict != NULL))
1442 g_HL2.SetEdictStateChanged(pEdict, offset);
1448 static cell_t GetEntPropVector(IPluginContext *pContext, const cell_t *params)
1450 CBaseEntity *pEntity;
1453 const char *class_name;
1456 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1458 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1461 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1466 pContext->LocalToString(params[3], &prop);
1472 typedescription_t *td;
1476 if (td->fieldType != FIELD_VECTOR
1477 && td->fieldType != FIELD_POSITION_VECTOR)
1479 return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])",
1483 FIELD_POSITION_VECTOR);
1486 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1491 sm_sendprop_info_t info;
1493 FIND_PROP_SEND(&info);
1495 if (info.prop->GetType() != DPT_Vector)
1497 return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
1499 info.prop->GetType(),
1503 offset = info.actual_offset;
1508 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1512 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
1515 pContext->LocalToPhysAddr(params[4], &vec);
1517 vec[0] = sp_ftoc(v->x);
1518 vec[1] = sp_ftoc(v->y);
1519 vec[2] = sp_ftoc(v->z);
1524 static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params)
1526 CBaseEntity *pEntity;
1529 const char *class_name;
1532 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1534 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1537 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1542 pContext->LocalToString(params[3], &prop);
1548 typedescription_t *td;
1552 if (td->fieldType != FIELD_VECTOR
1553 && td->fieldType != FIELD_POSITION_VECTOR)
1555 return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])",
1559 FIELD_POSITION_VECTOR);
1562 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1567 sm_sendprop_info_t info;
1569 FIND_PROP_SEND(&info);
1571 if (info.prop->GetType() != DPT_Vector)
1573 return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
1575 info.prop->GetType(),
1579 offset = info.actual_offset;
1584 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1588 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
1591 pContext->LocalToPhysAddr(params[4], &vec);
1593 v->x = sp_ctof(vec[0]);
1594 v->y = sp_ctof(vec[1]);
1595 v->z = sp_ctof(vec[2]);
1597 if (params[2] == Prop_Send && (pEdict != NULL))
1599 g_HL2.SetEdictStateChanged(pEdict, offset);
1605 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
1607 CBaseEntity *pEntity;
1610 const char *class_name;
1612 bool bIsStringIndex;
1614 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1616 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1619 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1624 pContext->LocalToString(params[3], &prop);
1626 bIsStringIndex = false;
1632 typedescription_t *td;
1636 if (td->fieldType != FIELD_CHARACTER
1637 && td->fieldType != FIELD_STRING
1638 && td->fieldType != FIELD_MODELNAME
1639 && td->fieldType != FIELD_SOUNDNAME)
1641 return pContext->ThrowNativeError("Data field %s is not a string (%d != %d)",
1647 bIsStringIndex = (td->fieldType != FIELD_CHARACTER);
1649 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1654 sm_sendprop_info_t info;
1656 FIND_PROP_SEND(&info);
1658 if (info.prop->GetType() != DPT_String)
1660 return pContext->ThrowNativeError("SendProp %s is not a string (%d != %d)",
1662 info.prop->GetType(),
1666 offset = info.actual_offset;
1672 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1679 if (!bIsStringIndex)
1681 src = (char *)((uint8_t *)pEntity + offset);
1687 idx = *(string_t *)((uint8_t *)pEntity + offset);
1688 src = (idx == NULL_STRING) ? "" : STRING(idx);
1691 pContext->StringToLocalUTF8(params[4], params[5], src, &len);
1696 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
1698 CBaseEntity *pEntity;
1704 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1706 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1714 typedescription_t *td;
1715 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
1717 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
1719 pContext->LocalToString(params[3], &prop);
1720 if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
1722 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
1724 if (td->fieldType != FIELD_CHARACTER)
1726 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
1728 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1729 maxlen = td->fieldSize;
1735 IServerUnknown *pUnk = (IServerUnknown *)pEntity;
1736 IServerNetworkable *pNet = pUnk->GetNetworkable();
1739 return pContext->ThrowNativeError("The edict is not networkable");
1741 pContext->LocalToString(params[3], &prop);
1742 SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
1745 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
1747 if (pSend->GetType() != DPT_String)
1749 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
1751 offset = pSend->GetOffset();
1752 maxlen = DT_MAX_STRING_BUFFERSIZE;
1757 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1762 char *dest = (char *)((uint8_t *)pEntity + offset);
1764 pContext->LocalToString(params[4], &src);
1765 size_t len = strncopy(dest, src, maxlen);
1767 if (params[2] == Prop_Send && (pEdict != NULL))
1769 g_HL2.SetEdictStateChanged(pEdict, offset);
1775 REGISTER_NATIVES(entityNatives)
1777 {"ChangeEdictState", ChangeEdictState},
1778 {"CreateEdict", CreateEdict},
1779 {"FindDataMapOffs", FindDataMapOffs},
1780 {"FindSendPropInfo", FindSendPropInfo},
1781 {"FindSendPropOffs", FindSendPropOffs},
1782 {"GetEdictClassname", GetEdictClassname},
1783 {"GetEdictFlags", GetEdictFlags},
1784 {"GetEntData", GetEntData},
1785 {"GetEntDataEnt", GetEntDataEnt}, /** DEPRECATED */
1786 {"GetEntDataEnt2", GetEntDataEnt2},
1787 {"GetEntDataFloat", GetEntDataFloat},
1788 {"GetEntDataString", GetEntDataString},
1789 {"GetEntDataVector", GetEntDataVector},
1790 {"GetEntProp", GetEntProp},
1791 {"GetEntPropEnt", GetEntPropEnt},
1792 {"GetEntPropFloat", GetEntPropFloat},
1793 {"GetEntPropString", GetEntPropString},
1794 {"GetEntPropVector", GetEntPropVector},
1795 {"GetEntityCount", GetEntityCount},
1796 {"GetEntityNetClass", GetEntityNetClass},
1797 {"GetMaxEntities", GetMaxEntities},
1798 {"IsEntNetworkable", IsEntNetworkable},
1799 {"IsValidEdict", IsValidEdict},
1800 {"IsValidEntity", IsValidEntity},
1801 {"RemoveEdict", RemoveEdict},
1802 {"SetEdictFlags", SetEdictFlags},
1803 {"SetEntData", SetEntData},
1804 {"SetEntDataEnt", SetEntDataEnt}, /** DEPRECATED */
1805 {"SetEntDataEnt2", SetEntDataEnt2},
1806 {"SetEntDataFloat", SetEntDataFloat},
1807 {"SetEntDataVector", SetEntDataVector},
1808 {"SetEntDataString", SetEntDataString},
1809 {"SetEntProp", SetEntProp},
1810 {"SetEntPropEnt", SetEntPropEnt},
1811 {"SetEntPropFloat", SetEntPropFloat},
1812 {"SetEntPropString", SetEntPropString},
1813 {"SetEntPropVector", SetEntPropVector},