3 * =============================================================================
5 * Copyright (C) 2004-2010 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 <IGameConfigs.h>
38 #include "sm_stringutil.h"
39 #include "logic_bridge.h"
49 PropField_Unsupported, /**< The type is unsupported. */
50 PropField_Integer, /**< Valid for SendProp and Data fields */
51 PropField_Float, /**< Valid for SendProp and Data fields */
52 PropField_Entity, /**< Valid for Data fields only (SendProp shows as int) */
53 PropField_Vector, /**< Valid for SendProp and Data fields */
54 PropField_String, /**< Valid for SendProp and Data fields */
55 PropField_String_T, /**< Valid for Data fields. Read only! */
58 inline edict_t *BaseEntityToEdict(CBaseEntity *pEntity)
60 IServerUnknown *pUnk = (IServerUnknown *)pEntity;
61 IServerNetworkable *pNet = pUnk->GetNetworkable();
68 return pNet->GetEdict();
71 inline edict_t *GetEdict(cell_t num)
74 if (!IndexToAThings(num, NULL, &pEdict))
82 inline CBaseEntity *GetEntity(cell_t num)
85 if (!IndexToAThings(num, &pEntity, NULL))
93 /* Given an entity reference or index, fill out a CBaseEntity and/or edict.
94 If lookup is successful, returns true and writes back the two parameters.
95 If lookup fails, returns false and doesn't touch the params. */
96 bool IndexToAThings(cell_t num, CBaseEntity **pEntData, edict_t **pEdictData)
98 CBaseEntity *pEntity = g_HL2.ReferenceToEntity(num);
105 int index = g_HL2.ReferenceToIndex(num);
106 if (index > 0 && index <= g_Players.GetMaxClients())
108 CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
109 if (!pPlayer || !pPlayer->IsConnected())
122 edict_t *pEdict = ::BaseEntityToEdict(pEntity);
123 if (!pEdict || pEdict->IsFree())
128 *pEdictData = pEdict;
134 <predcrab> AThings is like guaranteed r+ by dvander though
135 <predcrab> he wont even read the rest of the patch to nit stuff
136 <Fyren> Like I wasn't going to r? you anyway!
137 <predcrab> he still sees!
138 <predcrab> he's everywhere
141 class VEmptyClass {};
142 datamap_t *VGetDataDescMap(CBaseEntity *pThisPtr, int offset)
144 void **this_ptr = *reinterpret_cast<void ***>(&pThisPtr);
145 void **vtable = *reinterpret_cast<void ***>(pThisPtr);
146 void *vfunc = vtable[offset];
150 datamap_t *(VEmptyClass::*mfpnew)();
151 #ifndef PLATFORM_POSIX
166 return (datamap_t *)(reinterpret_cast<VEmptyClass *>(this_ptr)->*u.mfpnew)();
169 inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity)
173 if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset)
178 return VGetDataDescMap(pEntity, offset);
181 /* :TODO: Move this! */
182 datamap_t *CHalfLife2::GetDataMap(CBaseEntity *pEntity)
184 return CBaseEntity_GetDataDescMap(pEntity);
187 static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params)
189 return gpGlobals->maxEntities;
192 static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params)
194 edict_t *pEdict = engine->CreateEdict();
201 return IndexOfEdict(pEdict);
204 static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
206 edict_t *pEdict = GetEdict(params[1]);
210 return pContext->ThrowNativeError("Edict %d (%d) is not a valid edict", g_HL2.ReferenceToIndex(params[1]), params[1]);
213 engine->RemoveEdict(pEdict);
218 static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params)
220 edict_t *pEdict = GetEdict(params[1]);
227 /* Shouldn't be necessary... not sure though */
228 return pEdict->IsFree() ? 0 : 1;
231 static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
233 CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
235 return (pEntity != NULL) ? 1 : 0;
238 static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
240 edict_t *pEdict = GetEdict(params[1]);
247 return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
250 static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
252 return engine->GetEntityCount();
255 static cell_t GetEdictFlags(IPluginContext *pContext, const cell_t *params)
257 edict_t *pEdict = GetEdict(params[1]);
261 return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
264 return pEdict->m_fStateFlags;
267 static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params)
269 edict_t *pEdict = GetEdict(params[1]);
273 return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
276 pEdict->m_fStateFlags = params[2];
281 static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params)
283 edict_t *pEdict = GetEdict(params[1]);
287 return pContext->ThrowNativeError("Invalid edict (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
290 const char *cls = pEdict->GetClassName();
292 if (!cls || cls[0] == '\0')
297 pContext->StringToLocal(params[2], params[3], cls);
302 static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
304 CBaseEntity *pEntity = g_HL2.ReferenceToEntity(params[1]);
306 IServerUnknown *pUnk = (IServerUnknown *)pEntity;
310 return pContext->ThrowNativeError("Invalid entity (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
313 IServerNetworkable *pNet = pUnk->GetNetworkable();
319 ServerClass *pClass = pNet->GetServerClass();
321 pContext->StringToLocal(params[2], params[3], pClass->GetName());
326 static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
328 CBaseEntity *pEntity = GetEntity(params[1]);
332 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
335 int offset = params[2];
336 if (offset <= 0 || offset > 32768)
338 return pContext->ThrowNativeError("Offset %d is invalid", offset);
344 return *(int *)((uint8_t *)pEntity + offset);
346 return *(short *)((uint8_t *)pEntity + offset);
348 return *((uint8_t *)pEntity + offset);
350 return pContext->ThrowNativeError("Integer size %d is invalid", params[3]);
354 static cell_t SetEntData(IPluginContext *pContext, const cell_t *params)
356 CBaseEntity *pEntity;
359 if (!IndexToAThings(params[1], &pEntity, &pEdict))
361 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
364 int offset = params[2];
365 if (offset <= 0 || offset > 32768)
367 return pContext->ThrowNativeError("Offset %d is invalid", offset);
370 if (params[5] && (pEdict != NULL))
372 g_HL2.SetEdictStateChanged(pEdict, offset);
379 *(int *)((uint8_t *)pEntity + offset) = params[3];
384 *(short *)((uint8_t *)pEntity + offset) = params[3];
389 *((uint8_t *)pEntity + offset) = params[3];
393 return pContext->ThrowNativeError("Integer size %d is invalid", params[4]);
399 static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
401 CBaseEntity *pEntity = GetEntity(params[1]);
405 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
408 int offset = params[2];
409 if (offset <= 0 || offset > 32768)
411 return pContext->ThrowNativeError("Offset %d is invalid", offset);
414 float f = *(float *)((uint8_t *)pEntity + offset);
419 static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params)
421 CBaseEntity *pEntity;
424 if (!IndexToAThings(params[1], &pEntity, &pEdict))
426 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
429 int offset = params[2];
430 if (offset <= 0 || offset > 32768)
432 return pContext->ThrowNativeError("Offset %d is invalid", offset);
435 *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
437 if (params[4] && (pEdict != NULL))
439 g_HL2.SetEdictStateChanged(pEdict, offset);
445 static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
447 CBaseEntity *pEntity = GetEntity(params[1]);
451 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
454 int offset = params[2];
455 if (offset <= 0 || offset > 32768)
457 return pContext->ThrowNativeError("Offset %d is invalid", offset);
460 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
463 pContext->LocalToPhysAddr(params[3], &vec);
465 vec[0] = sp_ftoc(v->x);
466 vec[1] = sp_ftoc(v->y);
467 vec[2] = sp_ftoc(v->z);
472 static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params)
474 CBaseEntity *pEntity;
477 if (!IndexToAThings(params[1], &pEntity, &pEdict))
479 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
482 int offset = params[2];
483 if (offset <= 0 || offset > 32768)
485 return pContext->ThrowNativeError("Offset %d is invalid", offset);
488 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
491 pContext->LocalToPhysAddr(params[3], &vec);
493 v->x = sp_ctof(vec[0]);
494 v->y = sp_ctof(vec[1]);
495 v->z = sp_ctof(vec[2]);
497 if (params[4] && (pEdict != NULL))
499 g_HL2.SetEdictStateChanged(pEdict, offset);
505 /* THIS GUY IS DEPRECATED. */
506 static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
508 CBaseEntity *pEntity = GetEntity(params[1]);
512 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
515 int offset = params[2];
516 if (offset <= 0 || offset > 32768)
518 return pContext->ThrowNativeError("Offset %d is invalid", offset);
521 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
528 int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
529 return g_HL2.ReferenceToBCompatRef(ref);
532 int CheckBaseHandle(CBaseHandle &hndl)
539 int index = hndl.GetEntryIndex();
541 edict_t *pStoredEdict;
542 CBaseEntity *pStoredEntity;
544 if (!IndexToAThings(index, &pStoredEntity, &pStoredEdict))
549 if (pStoredEdict == NULL || pStoredEntity == NULL)
554 IServerEntity *pSE = pStoredEdict->GetIServerEntity();
561 if (pSE->GetRefEHandle() != hndl)
569 static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
571 CBaseEntity *pEntity = GetEntity(params[1]);
575 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
578 int offset = params[2];
579 if (offset <= 0 || offset > 32768)
581 return pContext->ThrowNativeError("Offset %d is invalid", offset);
584 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
586 int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
587 return g_HL2.ReferenceToBCompatRef(ref);
590 /* THIS GUY IS DEPRECATED. */
591 static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
593 CBaseEntity *pEntity;
596 if (!IndexToAThings(params[1], &pEntity, &pEdict))
598 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
601 int offset = params[2];
602 if (offset <= 0 || offset > 32768)
604 return pContext->ThrowNativeError("Offset %d is invalid", offset);
607 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
609 if (params[3] == 0 || (unsigned)params[3] == INVALID_EHANDLE_INDEX)
613 CBaseEntity *pOther = GetEntity(params[3]);
617 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[3]), params[3]);
620 IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
621 hndl.Set(pHandleEnt);
624 if (params[4] && (pEdict != NULL))
626 g_HL2.SetEdictStateChanged(pEdict, offset);
632 static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
634 CBaseEntity *pEntity;
637 if (!IndexToAThings(params[1], &pEntity, &pEdict))
639 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
642 int offset = params[2];
643 if (offset <= 0 || offset > 32768)
645 return pContext->ThrowNativeError("Offset %d is invalid", offset);
648 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
650 if ((unsigned)params[3] == INVALID_EHANDLE_INDEX)
656 CBaseEntity *pOther = GetEntity(params[3]);
660 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[3]), params[3]);
663 IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
664 hndl.Set(pHandleEnt);
667 if (params[4] && (pEdict != NULL))
669 g_HL2.SetEdictStateChanged(pEdict, offset);
675 static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
677 edict_t *pEdict = GetEdict(params[1]);
681 return pContext->ThrowNativeError("Edict %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
684 g_HL2.SetEdictStateChanged(pEdict, params[2]);
689 static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
692 pContext->LocalToString(params[1], &cls);
693 pContext->LocalToString(params[2], &prop);
695 SendProp *pSend = g_HL2.FindInSendTable(cls, prop);
702 return pSend->GetOffset();
705 static cell_t FindSendPropInfo(IPluginContext *pContext, const cell_t *params)
708 sm_sendprop_info_t info;
709 cell_t *pType, *pBits, *pLocal;
711 pContext->LocalToString(params[1], &cls);
712 pContext->LocalToString(params[2], &prop);
714 if (!g_HL2.FindSendPropInfo(cls, prop, &info))
719 pContext->LocalToPhysAddr(params[3], &pType);
720 pContext->LocalToPhysAddr(params[4], &pBits);
721 pContext->LocalToPhysAddr(params[5], &pLocal);
723 switch (info.prop->GetType())
727 *pType = PropField_Integer;
732 *pType = PropField_Float;
737 *pType = PropField_String;
742 *pType = PropField_Vector;
747 *pType = PropField_Unsupported;
752 *pBits = info.prop->m_nBits;
753 *pLocal = info.prop->GetOffset();
755 return info.actual_offset;
758 static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
760 CBaseEntity *pEntity;
762 typedescription_t *td;
764 pEntity = GetEntity(params[1]);
768 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
771 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
773 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
776 pContext->LocalToString(params[2], &offset);
777 if ((td=g_HL2.FindInDataMap(pMap, offset)) == NULL)
784 cell_t *pType, *pSize;
786 pContext->LocalToPhysAddr(params[3], &pType);
787 pContext->LocalToPhysAddr(params[4], &pSize);
789 switch (td->fieldType)
792 case FIELD_MODELINDEX:
793 case FIELD_MATERIALINDEX:
797 *pType = PropField_Integer;
802 case FIELD_POSITION_VECTOR:
804 *pType = PropField_Vector;
810 *pType = PropField_Integer;
816 *pType = PropField_Integer;
820 case FIELD_CHARACTER:
822 if (td->fieldSize == 1)
824 *pType = PropField_Integer;
829 *pType = PropField_String;
830 *pSize = 8 * td->fieldSize;
834 case FIELD_MODELNAME:
835 case FIELD_SOUNDNAME:
838 *pSize = sizeof(string_t);
839 *pType = PropField_String_T;
845 *pType = PropField_Float;
851 *pType = PropField_Entity;
857 *pType = PropField_Unsupported;
863 return GetTypeDescOffs(td);
866 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
868 CBaseEntity *pEntity = GetEntity(params[1]);
872 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
875 int offset = params[2];
876 if (offset < 0 || offset > 32768)
878 return pContext->ThrowNativeError("Offset %d is invalid", offset);
882 char *src = (char *)((uint8_t *)pEntity + offset);
883 pContext->StringToLocalUTF8(params[3], params[4], src, &len);
888 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
890 CBaseEntity *pEntity;
893 if (!IndexToAThings(params[1], &pEntity, &pEdict))
895 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
898 int offset = params[2];
899 if (offset < 0 || offset > 32768)
901 return pContext->ThrowNativeError("Offset %d is invalid", offset);
905 char *dest = (char *)((uint8_t *)pEntity + offset);
907 pContext->LocalToString(params[3], &src);
908 size_t len = strncopy(dest, src, params[4]);
910 if (params[5] && (pEdict != NULL))
912 g_HL2.SetEdictStateChanged(pEdict, offset);
918 #define FIND_PROP_DATA(td) \
920 if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL) \
922 return pContext->ThrowNativeError("Could not retrieve datamap"); \
924 if ((td = g_HL2.FindInDataMap(pMap, prop)) == NULL) \
926 return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
932 #define FIND_PROP_SEND(pProp) \
933 IServerUnknown *pUnk = (IServerUnknown *)pEntity; \
934 IServerNetworkable *pNet = pUnk->GetNetworkable(); \
937 return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); \
939 if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, pProp)) \
941 return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
947 inline int MatchFieldAsInteger(int field_type)
952 case FIELD_MODELINDEX:
953 case FIELD_MATERIALINDEX:
959 case FIELD_CHARACTER:
970 static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
972 CBaseEntity *pEntity;
975 const char *class_name;
979 if (!IndexToAThings(params[1], &pEntity, &pEdict))
981 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
984 /* TODO: Find a way to lookup classname without having an edict - Is this a guaranteed prop? */
985 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
990 pContext->LocalToString(params[3], &prop);
996 typedescription_t *td;
1000 if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
1002 return pContext->ThrowNativeError("Data field %s is not an integer (%d)",
1007 offset = GetTypeDescOffs(td);
1012 sm_sendprop_info_t info;
1014 FIND_PROP_SEND(&info);
1016 if (info.prop->GetType() != DPT_Int)
1018 return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
1020 info.prop->GetType(),
1025 bit_count = info.prop->m_nBits;
1026 offset = info.actual_offset;
1031 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1037 bit_count = params[4] * 8;
1040 if (bit_count >= 17)
1042 return *(int32_t *)((uint8_t *)pEntity + offset);
1044 else if (bit_count >= 9)
1046 return *(int16_t *)((uint8_t *)pEntity + offset);
1048 else if (bit_count >= 2)
1050 return *(int8_t *)((uint8_t *)pEntity + offset);
1054 return *(bool *)((uint8_t *)pEntity + offset) ? 1 : 0;
1060 static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
1062 CBaseEntity *pEntity;
1065 const char *class_name;
1069 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1071 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1074 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1079 pContext->LocalToString(params[3], &prop);
1085 typedescription_t *td;
1089 if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
1091 return pContext->ThrowNativeError("Data field %s is not an integer (%d)",
1096 offset = GetTypeDescOffs(td);
1101 sm_sendprop_info_t info;
1103 FIND_PROP_SEND(&info);
1105 if (info.prop->GetType() != DPT_Int)
1107 return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
1109 info.prop->GetType(),
1114 bit_count = info.prop->m_nBits;
1115 offset = info.actual_offset;
1120 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1126 bit_count = params[5] * 8;
1129 if (bit_count >= 17)
1131 *(int32_t *)((uint8_t *)pEntity + offset) = params[4];
1133 else if (bit_count >= 9)
1135 *(int16_t *)((uint8_t *)pEntity + offset) = (int16_t)params[4];
1137 else if (bit_count >= 2)
1139 *(int8_t *)((uint8_t *)pEntity + offset) = (int8_t)params[4];
1143 *(bool *)((uint8_t *)pEntity + offset) = params[4] ? true : false;
1149 static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params)
1151 CBaseEntity *pEntity;
1154 const char *class_name;
1157 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1159 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1162 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1167 pContext->LocalToString(params[3], &prop);
1173 typedescription_t *td;
1177 if (td->fieldType != FIELD_FLOAT
1178 && td->fieldType != FIELD_TIME)
1180 return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])",
1187 offset = GetTypeDescOffs(td);
1192 sm_sendprop_info_t info;
1194 FIND_PROP_SEND(&info);
1196 if (info.prop->GetType() != DPT_Float)
1198 return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
1200 info.prop->GetType(),
1204 offset = info.actual_offset;
1209 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1213 float val = *(float *)((uint8_t *)pEntity + offset);
1215 return sp_ftoc(val);
1218 static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params)
1220 CBaseEntity *pEntity;
1223 const char *class_name;
1226 if (!IndexToAThings(params[1], &pEntity, &pEdict))
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 = GetTypeDescOffs(td);
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 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1302 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1305 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1310 pContext->LocalToString(params[3], &prop);
1316 typedescription_t *td;
1320 if (td->fieldType != FIELD_EHANDLE)
1322 return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)",
1328 offset = GetTypeDescOffs(td);
1333 sm_sendprop_info_t info;
1335 FIND_PROP_SEND(&info);
1337 if (info.prop->GetType() != DPT_Int)
1339 return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
1341 info.prop->GetType(),
1345 offset = info.actual_offset;
1350 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1354 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
1356 int ref = g_HL2.IndexToReference(hndl.GetEntryIndex());
1357 return g_HL2.ReferenceToBCompatRef(ref);
1360 static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
1362 CBaseEntity *pEntity;
1365 const char *class_name;
1368 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1370 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1373 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1378 pContext->LocalToString(params[3], &prop);
1384 typedescription_t *td;
1388 if (td->fieldType != FIELD_EHANDLE)
1390 return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)",
1396 offset = GetTypeDescOffs(td);
1401 sm_sendprop_info_t info;
1403 FIND_PROP_SEND(&info);
1405 if (info.prop->GetType() != DPT_Int)
1407 return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
1409 info.prop->GetType(),
1413 offset = info.actual_offset;
1418 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1422 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
1424 if (params[4] == -1)
1430 CBaseEntity *pOther = GetEntity(params[4]);
1434 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[4]), params[4]);
1437 IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
1438 hndl.Set(pHandleEnt);
1441 if (params[2] == Prop_Send && (pEdict != NULL))
1443 g_HL2.SetEdictStateChanged(pEdict, offset);
1449 static cell_t GetEntPropVector(IPluginContext *pContext, const cell_t *params)
1451 CBaseEntity *pEntity;
1454 const char *class_name;
1457 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1459 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1462 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1467 pContext->LocalToString(params[3], &prop);
1473 typedescription_t *td;
1477 if (td->fieldType != FIELD_VECTOR
1478 && td->fieldType != FIELD_POSITION_VECTOR)
1480 return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])",
1484 FIELD_POSITION_VECTOR);
1487 offset = GetTypeDescOffs(td);
1492 sm_sendprop_info_t info;
1494 FIND_PROP_SEND(&info);
1496 if (info.prop->GetType() != DPT_Vector)
1498 return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
1500 info.prop->GetType(),
1504 offset = info.actual_offset;
1509 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1513 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
1516 pContext->LocalToPhysAddr(params[4], &vec);
1518 vec[0] = sp_ftoc(v->x);
1519 vec[1] = sp_ftoc(v->y);
1520 vec[2] = sp_ftoc(v->z);
1525 static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params)
1527 CBaseEntity *pEntity;
1530 const char *class_name;
1533 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1535 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1538 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1543 pContext->LocalToString(params[3], &prop);
1549 typedescription_t *td;
1553 if (td->fieldType != FIELD_VECTOR
1554 && td->fieldType != FIELD_POSITION_VECTOR)
1556 return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])",
1560 FIELD_POSITION_VECTOR);
1563 offset = GetTypeDescOffs(td);
1568 sm_sendprop_info_t info;
1570 FIND_PROP_SEND(&info);
1572 if (info.prop->GetType() != DPT_Vector)
1574 return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
1576 info.prop->GetType(),
1580 offset = info.actual_offset;
1585 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1589 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
1592 pContext->LocalToPhysAddr(params[4], &vec);
1594 v->x = sp_ctof(vec[0]);
1595 v->y = sp_ctof(vec[1]);
1596 v->z = sp_ctof(vec[2]);
1598 if (params[2] == Prop_Send && (pEdict != NULL))
1600 g_HL2.SetEdictStateChanged(pEdict, offset);
1606 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
1608 CBaseEntity *pEntity;
1611 const char *class_name;
1613 bool bIsStringIndex;
1615 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1617 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1620 if (!pEdict || (class_name = pEdict->GetClassName()) == NULL)
1625 pContext->LocalToString(params[3], &prop);
1627 bIsStringIndex = false;
1633 typedescription_t *td;
1637 if (td->fieldType != FIELD_CHARACTER
1638 && td->fieldType != FIELD_STRING
1639 && td->fieldType != FIELD_MODELNAME
1640 && td->fieldType != FIELD_SOUNDNAME)
1642 return pContext->ThrowNativeError("Data field %s is not a string (%d != %d)",
1648 bIsStringIndex = (td->fieldType != FIELD_CHARACTER);
1650 offset = GetTypeDescOffs(td);
1655 sm_sendprop_info_t info;
1657 FIND_PROP_SEND(&info);
1659 if (info.prop->GetType() != DPT_String)
1661 return pContext->ThrowNativeError("SendProp %s is not a string (%d != %d)",
1663 info.prop->GetType(),
1667 offset = info.actual_offset;
1673 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1680 if (!bIsStringIndex)
1682 src = (char *)((uint8_t *)pEntity + offset);
1688 idx = *(string_t *)((uint8_t *)pEntity + offset);
1689 src = (idx == NULL_STRING) ? "" : STRING(idx);
1692 pContext->StringToLocalUTF8(params[4], params[5], src, &len);
1697 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
1699 CBaseEntity *pEntity;
1705 if (!IndexToAThings(params[1], &pEntity, &pEdict))
1707 return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]);
1715 typedescription_t *td;
1716 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
1718 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
1720 pContext->LocalToString(params[3], &prop);
1721 if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
1723 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
1725 if (td->fieldType != FIELD_CHARACTER)
1727 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
1729 offset = GetTypeDescOffs(td);
1730 maxlen = td->fieldSize;
1736 IServerUnknown *pUnk = (IServerUnknown *)pEntity;
1737 IServerNetworkable *pNet = pUnk->GetNetworkable();
1740 return pContext->ThrowNativeError("The edict is not networkable");
1742 pContext->LocalToString(params[3], &prop);
1743 SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
1746 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
1748 if (pSend->GetType() != DPT_String)
1750 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
1752 offset = pSend->GetOffset();
1753 maxlen = DT_MAX_STRING_BUFFERSIZE;
1758 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1763 char *dest = (char *)((uint8_t *)pEntity + offset);
1765 pContext->LocalToString(params[4], &src);
1766 size_t len = strncopy(dest, src, maxlen);
1768 if (params[2] == Prop_Send && (pEdict != NULL))
1770 g_HL2.SetEdictStateChanged(pEdict, offset);
1776 REGISTER_NATIVES(entityNatives)
1778 {"ChangeEdictState", ChangeEdictState},
1779 {"CreateEdict", CreateEdict},
1780 {"FindDataMapOffs", FindDataMapOffs},
1781 {"FindSendPropInfo", FindSendPropInfo},
1782 {"FindSendPropOffs", FindSendPropOffs},
1783 {"GetEdictClassname", GetEdictClassname},
1784 {"GetEdictFlags", GetEdictFlags},
1785 {"GetEntData", GetEntData},
1786 {"GetEntDataEnt", GetEntDataEnt}, /** DEPRECATED */
1787 {"GetEntDataEnt2", GetEntDataEnt2},
1788 {"GetEntDataFloat", GetEntDataFloat},
1789 {"GetEntDataString", GetEntDataString},
1790 {"GetEntDataVector", GetEntDataVector},
1791 {"GetEntProp", GetEntProp},
1792 {"GetEntPropEnt", GetEntPropEnt},
1793 {"GetEntPropFloat", GetEntPropFloat},
1794 {"GetEntPropString", GetEntPropString},
1795 {"GetEntPropVector", GetEntPropVector},
1796 {"GetEntityCount", GetEntityCount},
1797 {"GetEntityNetClass", GetEntityNetClass},
1798 {"GetMaxEntities", GetMaxEntities},
1799 {"IsEntNetworkable", IsEntNetworkable},
1800 {"IsValidEdict", IsValidEdict},
1801 {"IsValidEntity", IsValidEntity},
1802 {"RemoveEdict", RemoveEdict},
1803 {"SetEdictFlags", SetEdictFlags},
1804 {"SetEntData", SetEntData},
1805 {"SetEntDataEnt", SetEntDataEnt}, /** DEPRECATED */
1806 {"SetEntDataEnt2", SetEntDataEnt2},
1807 {"SetEntDataFloat", SetEntDataFloat},
1808 {"SetEntDataVector", SetEntDataVector},
1809 {"SetEntDataString", SetEntDataString},
1810 {"SetEntProp", SetEntProp},
1811 {"SetEntPropEnt", SetEntPropEnt},
1812 {"SetEntPropFloat", SetEntPropFloat},
1813 {"SetEntPropString", SetEntPropString},
1814 {"SetEntPropVector", SetEntPropVector},