3 * =============================================================================
5 * Copyright (C) 2004-2007 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 "server_class.h"
36 #include "PlayerManager.h"
37 #include "HalfLife2.h"
38 #include "GameConfigs.h"
39 #include "sm_stringutil.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 *GetEdict(cell_t num)
60 edict_t *pEdict = engine->PEntityOfEntIndex(num);
61 if (!pEdict || pEdict->IsFree())
65 if (num > 0 && num <= g_Players.GetMaxClients())
67 CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
68 if (!pPlayer || !pPlayer->IsConnected())
76 inline edict_t *GetEntity(cell_t num, CBaseEntity **pData)
78 edict_t *pEdict = engine->PEntityOfEntIndex(num);
79 if (!pEdict || pEdict->IsFree())
83 if (num > 0 && num <= g_Players.GetMaxClients())
85 CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
86 if (!pPlayer || !pPlayer->IsConnected())
92 if ((pUnk=pEdict->GetUnknown()) == NULL)
96 *pData = pUnk->GetBaseEntity();
100 class VEmptyClass {};
101 datamap_t *VGetDataDescMap(CBaseEntity *pThisPtr, int offset)
103 void **this_ptr = *reinterpret_cast<void ***>(&pThisPtr);
104 void **vtable = *reinterpret_cast<void ***>(pThisPtr);
105 void *vfunc = vtable[offset];
109 datamap_t *(VEmptyClass::*mfpnew)();
110 #ifndef PLATFORM_POSIX
125 return (datamap_t *)(reinterpret_cast<VEmptyClass *>(this_ptr)->*u.mfpnew)();
128 inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity)
132 if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset)
137 return VGetDataDescMap(pEntity, offset);
140 /* :TODO: Move this! */
141 datamap_t *CHalfLife2::GetDataMap(CBaseEntity *pEntity)
143 return CBaseEntity_GetDataDescMap(pEntity);
146 static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params)
148 return gpGlobals->maxEntities;
151 static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params)
153 edict_t *pEdict = engine->CreateEdict();
160 return engine->IndexOfEdict(pEdict);
163 static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
165 edict_t *pEdict = engine->PEntityOfEntIndex(params[1]);
169 return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]);
172 engine->RemoveEdict(pEdict);
177 static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params)
179 edict_t *pEdict = GetEdict(params[1]);
186 /* Shouldn't be necessary... not sure though */
187 return pEdict->IsFree() ? 0 : 1;
190 static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
192 edict_t *pEdict = GetEdict(params[1]);
199 IServerUnknown *pUnknown = pEdict->GetUnknown();
205 CBaseEntity *pEntity = pUnknown->GetBaseEntity();
206 return (pEntity != NULL) ? 1 : 0;
209 static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
211 edict_t *pEdict = GetEdict(params[1]);
218 return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
221 static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
223 return engine->GetEntityCount();
226 static cell_t GetEdictFlags(IPluginContext *pContext, const cell_t *params)
228 edict_t *pEdict = GetEdict(params[1]);
232 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
235 return pEdict->m_fStateFlags;
238 static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params)
240 edict_t *pEdict = GetEdict(params[1]);
244 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
247 pEdict->m_fStateFlags = params[2];
252 static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params)
254 edict_t *pEdict = GetEdict(params[1]);
258 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
261 const char *cls = pEdict->GetClassName();
263 if (!cls || cls[0] == '\0')
268 pContext->StringToLocal(params[2], params[3], cls);
273 static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
275 edict_t *pEdict = GetEdict(params[1]);
279 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
282 IServerNetworkable *pNet = pEdict->GetNetworkable();
288 ServerClass *pClass = pNet->GetServerClass();
290 pContext->StringToLocal(params[2], params[3], pClass->GetName());
295 static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
297 CBaseEntity *pEntity;
298 edict_t *pEdict = GetEntity(params[1], &pEntity);
300 if (!pEdict || !pEntity)
302 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
305 int offset = params[2];
306 if (offset <= 0 || offset > 32768)
308 return pContext->ThrowNativeError("Offset %d is invalid", offset);
314 return *(int *)((uint8_t *)pEntity + offset);
316 return *(short *)((uint8_t *)pEntity + offset);
318 return *((uint8_t *)pEntity + offset);
320 return pContext->ThrowNativeError("Integer size %d is invalid", params[3]);
324 static cell_t SetEntData(IPluginContext *pContext, const cell_t *params)
326 CBaseEntity *pEntity;
327 edict_t *pEdict = GetEntity(params[1], &pEntity);
329 if (!pEdict || !pEntity)
331 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
334 int offset = params[2];
335 if (offset <= 0 || offset > 32768)
337 return pContext->ThrowNativeError("Offset %d is invalid", offset);
342 g_HL2.SetEdictStateChanged(pEdict, offset);
349 *(int *)((uint8_t *)pEntity + offset) = params[3];
354 *(short *)((uint8_t *)pEntity + offset) = params[3];
359 *((uint8_t *)pEntity + offset) = params[3];
363 return pContext->ThrowNativeError("Integer size %d is invalid", params[4]);
369 static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
371 CBaseEntity *pEntity;
372 edict_t *pEdict = GetEntity(params[1], &pEntity);
374 if (!pEdict || !pEntity)
376 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
379 int offset = params[2];
380 if (offset <= 0 || offset > 32768)
382 return pContext->ThrowNativeError("Offset %d is invalid", offset);
385 float f = *(float *)((uint8_t *)pEntity + offset);
390 static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params)
392 CBaseEntity *pEntity;
393 edict_t *pEdict = GetEntity(params[1], &pEntity);
395 if (!pEdict || !pEntity)
397 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
400 int offset = params[2];
401 if (offset <= 0 || offset > 32768)
403 return pContext->ThrowNativeError("Offset %d is invalid", offset);
406 *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
410 g_HL2.SetEdictStateChanged(pEdict, offset);
416 static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
418 CBaseEntity *pEntity;
419 edict_t *pEdict = GetEntity(params[1], &pEntity);
421 if (!pEdict || !pEntity)
423 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
426 int offset = params[2];
427 if (offset <= 0 || offset > 32768)
429 return pContext->ThrowNativeError("Offset %d is invalid", offset);
432 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
435 pContext->LocalToPhysAddr(params[3], &vec);
437 vec[0] = sp_ftoc(v->x);
438 vec[1] = sp_ftoc(v->y);
439 vec[2] = sp_ftoc(v->z);
444 static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params)
446 CBaseEntity *pEntity;
447 edict_t *pEdict = GetEntity(params[1], &pEntity);
449 if (!pEdict || !pEntity)
451 return pContext->ThrowNativeError("Entity %d is invalid", 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 v->x = sp_ctof(vec[0]);
466 v->y = sp_ctof(vec[1]);
467 v->z = sp_ctof(vec[2]);
471 g_HL2.SetEdictStateChanged(pEdict, offset);
477 /* THIS GUY IS DEPRECATED. */
478 static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
480 CBaseEntity *pEntity;
481 edict_t *pEdict = GetEntity(params[1], &pEntity);
483 if (!pEdict || !pEntity)
485 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
488 int offset = params[2];
489 if (offset <= 0 || offset > 32768)
491 return pContext->ThrowNativeError("Offset %d is invalid", offset);
494 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
501 return hndl.GetEntryIndex();
504 int CheckBaseHandle(CBaseHandle &hndl)
511 int index = hndl.GetEntryIndex();
513 edict_t *pStoredEdict;
514 CBaseEntity *pStoredEntity;
516 pStoredEdict = GetEntity(index, &pStoredEntity);
518 if (pStoredEdict == NULL || pStoredEntity == NULL)
523 IServerEntity *pSE = pStoredEdict->GetIServerEntity();
530 if (pSE->GetRefEHandle() != hndl)
538 static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
540 CBaseEntity *pEntity;
541 edict_t *pEdict = GetEntity(params[1], &pEntity);
543 if (pEdict == NULL || pEntity == NULL)
545 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
548 int offset = params[2];
549 if (offset <= 0 || offset > 32768)
551 return pContext->ThrowNativeError("Offset %d is invalid", offset);
554 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
556 return CheckBaseHandle(hndl);
559 /* THIS GUY IS DEPRECATED. */
560 static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
562 CBaseEntity *pEntity;
563 edict_t *pEdict = GetEntity(params[1], &pEntity);
565 if (!pEdict || !pEntity)
567 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
570 int offset = params[2];
571 if (offset <= 0 || offset > 32768)
573 return pContext->ThrowNativeError("Offset %d is invalid", offset);
576 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
582 edict_t *pEdict = GetEdict(params[3]);
585 return pContext->ThrowNativeError("Entity %d is invalid", params[3]);
587 IServerEntity *pEntOther = pEdict->GetIServerEntity();
593 g_HL2.SetEdictStateChanged(pEdict, offset);
599 static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
601 CBaseEntity *pEntity;
602 edict_t *pEdict = GetEntity(params[1], &pEntity);
604 if (!pEdict || !pEntity)
606 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
609 int offset = params[2];
610 if (offset <= 0 || offset > 32768)
612 return pContext->ThrowNativeError("Offset %d is invalid", offset);
615 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
623 edict_t *pEdict = GetEdict(params[3]);
626 return pContext->ThrowNativeError("Entity %d is invalid", params[3]);
628 IServerEntity *pEntOther = pEdict->GetIServerEntity();
634 g_HL2.SetEdictStateChanged(pEdict, offset);
640 static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
642 edict_t *pEdict = GetEdict(params[1]);
646 return pContext->ThrowNativeError("Edict %d is invalid", params[1]);
649 g_HL2.SetEdictStateChanged(pEdict, params[2]);
654 static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
657 pContext->LocalToString(params[1], &cls);
658 pContext->LocalToString(params[2], &prop);
660 SendProp *pSend = g_HL2.FindInSendTable(cls, prop);
667 return pSend->GetOffset();
670 static cell_t FindSendPropInfo(IPluginContext *pContext, const cell_t *params)
673 sm_sendprop_info_t info;
674 cell_t *pType, *pBits, *pLocal;
676 pContext->LocalToString(params[1], &cls);
677 pContext->LocalToString(params[2], &prop);
679 if (!g_HL2.FindSendPropInfo(cls, prop, &info))
684 pContext->LocalToPhysAddr(params[3], &pType);
685 pContext->LocalToPhysAddr(params[4], &pBits);
686 pContext->LocalToPhysAddr(params[5], &pLocal);
688 switch (info.prop->GetType())
692 *pType = PropField_Integer;
697 *pType = PropField_Float;
702 *pType = PropField_String;
707 *pType = PropField_Vector;
712 *pType = PropField_Unsupported;
717 *pBits = info.prop->m_nBits;
718 *pLocal = info.prop->GetOffset();
720 return info.actual_offset;
723 static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
725 CBaseEntity *pEntity;
727 typedescription_t *td;
729 edict_t *pEdict = GetEntity(params[1], &pEntity);
731 if (!pEdict || !pEntity)
733 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
736 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
738 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
741 pContext->LocalToString(params[2], &offset);
742 if ((td=g_HL2.FindInDataMap(pMap, offset)) == NULL)
749 cell_t *pType, *pSize;
751 pContext->LocalToPhysAddr(params[3], &pType);
752 pContext->LocalToPhysAddr(params[4], &pSize);
754 switch (td->fieldType)
757 case FIELD_MODELINDEX:
758 case FIELD_MATERIALINDEX:
762 *pType = PropField_Integer;
767 case FIELD_POSITION_VECTOR:
769 *pType = PropField_Vector;
775 *pType = PropField_Integer;
781 *pType = PropField_Integer;
785 case FIELD_CHARACTER:
787 if (td->fieldSize == 1)
789 *pType = PropField_Integer;
794 *pType = PropField_String;
795 *pSize = 8 * td->fieldSize;
799 case FIELD_MODELNAME:
800 case FIELD_SOUNDNAME:
803 *pSize = sizeof(string_t);
804 *pType = PropField_String_T;
810 *pType = PropField_Float;
816 *pType = PropField_Entity;
822 *pType = PropField_Unsupported;
828 return td->fieldOffset[TD_OFFSET_NORMAL];
831 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
833 CBaseEntity *pEntity;
834 edict_t *pEdict = GetEntity(params[1], &pEntity);
836 if (!pEdict || !pEntity)
838 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
841 int offset = params[2];
842 if (offset < 0 || offset > 32768)
844 return pContext->ThrowNativeError("Offset %d is invalid", offset);
848 char *src = (char *)((uint8_t *)pEntity + offset);
849 pContext->StringToLocalUTF8(params[3], params[4], src, &len);
854 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
856 CBaseEntity *pEntity;
857 edict_t *pEdict = GetEntity(params[1], &pEntity);
859 if (!pEdict || !pEntity)
861 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
864 int offset = params[2];
865 if (offset < 0 || offset > 32768)
867 return pContext->ThrowNativeError("Offset %d is invalid", offset);
871 char *dest = (char *)((uint8_t *)pEntity + offset);
873 pContext->LocalToString(params[3], &src);
874 size_t len = strncopy(dest, src, params[4]);
878 g_HL2.SetEdictStateChanged(pEdict, offset);
884 #define FIND_PROP_DATA(td) \
886 if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL) \
888 return pContext->ThrowNativeError("Could not retrieve datamap"); \
890 if ((td = g_HL2.FindInDataMap(pMap, prop)) == NULL) \
892 return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
898 #define FIND_PROP_SEND(pProp) \
899 IServerNetworkable *pNet = pEdict->GetNetworkable(); \
902 return pContext->ThrowNativeError("Edict %d is not networkable", params[1]); \
904 if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, pProp)) \
906 return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
912 inline int MatchFieldAsInteger(int field_type)
917 case FIELD_MODELINDEX:
918 case FIELD_MATERIALINDEX:
924 case FIELD_CHARACTER:
935 static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
937 CBaseEntity *pEntity;
940 const char *class_name;
944 pEdict = GetEntity(params[1], &pEntity);
946 if (!pEdict || !pEntity)
948 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
951 if ((class_name = pEdict->GetClassName()) == NULL)
956 pContext->LocalToString(params[3], &prop);
962 typedescription_t *td;
966 if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
968 return pContext->ThrowNativeError("Data field %s is not an integer (%d)",
973 offset = td->fieldOffset[TD_OFFSET_NORMAL];
978 sm_sendprop_info_t info;
980 FIND_PROP_SEND(&info);
982 if (info.prop->GetType() != DPT_Int)
984 return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
986 info.prop->GetType(),
991 bit_count = info.prop->m_nBits;
992 offset = info.actual_offset;
997 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1003 bit_count = params[4] * 8;
1006 if (bit_count >= 17)
1008 return *(int32_t *)((uint8_t *)pEntity + offset);
1010 else if (bit_count >= 9)
1012 return *(int16_t *)((uint8_t *)pEntity + offset);
1014 else if (bit_count >= 2)
1016 return *(int8_t *)((uint8_t *)pEntity + offset);
1020 return *(bool *)((uint8_t *)pEntity + offset) ? 1 : 0;
1026 static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
1028 CBaseEntity *pEntity;
1031 const char *class_name;
1035 pEdict = GetEntity(params[1], &pEntity);
1037 if (!pEdict || !pEntity)
1039 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
1042 if ((class_name = pEdict->GetClassName()) == NULL)
1047 pContext->LocalToString(params[3], &prop);
1053 typedescription_t *td;
1057 if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
1059 return pContext->ThrowNativeError("Data field %s is not an integer (%d)",
1064 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1069 sm_sendprop_info_t info;
1071 FIND_PROP_SEND(&info);
1073 if (info.prop->GetType() != DPT_Int)
1075 return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
1077 info.prop->GetType(),
1082 bit_count = info.prop->m_nBits;
1083 offset = info.actual_offset;
1088 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1094 bit_count = params[5] * 8;
1097 if (bit_count >= 17)
1099 *(int32_t *)((uint8_t *)pEntity + offset) = params[4];
1101 else if (bit_count >= 9)
1103 *(int16_t *)((uint8_t *)pEntity + offset) = (int16_t)params[4];
1105 else if (bit_count >= 2)
1107 *(int8_t *)((uint8_t *)pEntity + offset) = (int8_t)params[4];
1111 *(bool *)((uint8_t *)pEntity + offset) = params[4] ? true : false;
1117 static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params)
1119 CBaseEntity *pEntity;
1122 const char *class_name;
1125 pEdict = GetEntity(params[1], &pEntity);
1127 if (!pEdict || !pEntity)
1129 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
1132 if ((class_name = pEdict->GetClassName()) == NULL)
1137 pContext->LocalToString(params[3], &prop);
1143 typedescription_t *td;
1147 if (td->fieldType != FIELD_FLOAT
1148 && td->fieldType != FIELD_TIME)
1150 return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])",
1157 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1162 sm_sendprop_info_t info;
1164 FIND_PROP_SEND(&info);
1166 if (info.prop->GetType() != DPT_Float)
1168 return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
1170 info.prop->GetType(),
1174 offset = info.actual_offset;
1179 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1183 float val = *(float *)((uint8_t *)pEntity + offset);
1185 return sp_ftoc(val);
1188 static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params)
1190 CBaseEntity *pEntity;
1193 const char *class_name;
1196 pEdict = GetEntity(params[1], &pEntity);
1198 if (!pEdict || !pEntity)
1200 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
1203 if ((class_name = pEdict->GetClassName()) == NULL)
1208 pContext->LocalToString(params[3], &prop);
1214 typedescription_t *td;
1218 if (td->fieldType != FIELD_FLOAT
1219 && td->fieldType != FIELD_TIME)
1221 return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])",
1228 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1233 sm_sendprop_info_t info;
1235 FIND_PROP_SEND(&info);
1237 if (info.prop->GetType() != DPT_Float)
1239 return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
1241 info.prop->GetType(),
1245 offset = info.actual_offset;
1250 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1254 *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[4]);
1256 if (params[2] == Prop_Send)
1258 g_HL2.SetEdictStateChanged(pEdict, offset);
1264 static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params)
1266 CBaseEntity *pEntity;
1269 const char *class_name;
1272 pEdict = GetEntity(params[1], &pEntity);
1274 if (!pEdict || !pEntity)
1276 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
1279 if ((class_name = pEdict->GetClassName()) == NULL)
1284 pContext->LocalToString(params[3], &prop);
1290 typedescription_t *td;
1294 if (td->fieldType != FIELD_EHANDLE)
1296 return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)",
1302 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1307 sm_sendprop_info_t info;
1309 FIND_PROP_SEND(&info);
1311 if (info.prop->GetType() != DPT_Int)
1313 return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
1315 info.prop->GetType(),
1319 offset = info.actual_offset;
1324 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1328 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
1330 return CheckBaseHandle(hndl);
1333 static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
1335 CBaseEntity *pEntity;
1338 const char *class_name;
1341 pEdict = GetEntity(params[1], &pEntity);
1343 if (!pEdict || !pEntity)
1345 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
1348 if ((class_name = pEdict->GetClassName()) == NULL)
1353 pContext->LocalToString(params[3], &prop);
1359 typedescription_t *td;
1363 if (td->fieldType != FIELD_EHANDLE)
1365 return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)",
1371 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1376 sm_sendprop_info_t info;
1378 FIND_PROP_SEND(&info);
1380 if (info.prop->GetType() != DPT_Int)
1382 return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
1384 info.prop->GetType(),
1388 offset = info.actual_offset;
1393 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1397 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
1399 if (params[4] == -1)
1406 CBaseEntity *pOtherEnt;
1408 if ((pOther = GetEntity(params[4], &pOtherEnt)) == NULL)
1410 return pContext->ThrowNativeError("Invalid entity %d", params[4]);
1413 hndl.Set(pOther->GetIServerEntity());
1416 if (params[2] == Prop_Send)
1418 g_HL2.SetEdictStateChanged(pEdict, offset);
1424 static cell_t GetEntPropVector(IPluginContext *pContext, const cell_t *params)
1426 CBaseEntity *pEntity;
1429 const char *class_name;
1432 pEdict = GetEntity(params[1], &pEntity);
1434 if (!pEdict || !pEntity)
1436 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
1439 if ((class_name = pEdict->GetClassName()) == NULL)
1444 pContext->LocalToString(params[3], &prop);
1450 typedescription_t *td;
1454 if (td->fieldType != FIELD_VECTOR
1455 && td->fieldType != FIELD_POSITION_VECTOR)
1457 return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])",
1461 FIELD_POSITION_VECTOR);
1464 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1469 sm_sendprop_info_t info;
1471 FIND_PROP_SEND(&info);
1473 if (info.prop->GetType() != DPT_Vector)
1475 return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
1477 info.prop->GetType(),
1481 offset = info.actual_offset;
1486 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1490 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
1493 pContext->LocalToPhysAddr(params[4], &vec);
1495 vec[0] = sp_ftoc(v->x);
1496 vec[1] = sp_ftoc(v->y);
1497 vec[2] = sp_ftoc(v->z);
1502 static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params)
1504 CBaseEntity *pEntity;
1507 const char *class_name;
1510 pEdict = GetEntity(params[1], &pEntity);
1512 if (!pEdict || !pEntity)
1514 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
1517 if ((class_name = pEdict->GetClassName()) == NULL)
1522 pContext->LocalToString(params[3], &prop);
1528 typedescription_t *td;
1532 if (td->fieldType != FIELD_VECTOR
1533 && td->fieldType != FIELD_POSITION_VECTOR)
1535 return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])",
1539 FIELD_POSITION_VECTOR);
1542 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1547 sm_sendprop_info_t info;
1549 FIND_PROP_SEND(&info);
1551 if (info.prop->GetType() != DPT_Vector)
1553 return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
1555 info.prop->GetType(),
1559 offset = info.actual_offset;
1564 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1568 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
1571 pContext->LocalToPhysAddr(params[4], &vec);
1573 v->x = sp_ctof(vec[0]);
1574 v->y = sp_ctof(vec[1]);
1575 v->z = sp_ctof(vec[2]);
1577 if (params[2] == Prop_Send)
1579 g_HL2.SetEdictStateChanged(pEdict, offset);
1585 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
1587 CBaseEntity *pEntity;
1590 const char *class_name;
1592 bool bIsStringIndex;
1594 pEdict = GetEntity(params[1], &pEntity);
1596 if (!pEdict || !pEntity)
1598 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
1601 if ((class_name = pEdict->GetClassName()) == NULL)
1606 pContext->LocalToString(params[3], &prop);
1608 bIsStringIndex = false;
1614 typedescription_t *td;
1618 if (td->fieldType != FIELD_CHARACTER
1619 && td->fieldType != FIELD_STRING
1620 && td->fieldType != FIELD_MODELNAME
1621 && td->fieldType != FIELD_SOUNDNAME)
1623 return pContext->ThrowNativeError("Data field %s is not a string (%d != %d)",
1629 bIsStringIndex = (td->fieldType != FIELD_CHARACTER);
1631 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1636 sm_sendprop_info_t info;
1638 FIND_PROP_SEND(&info);
1640 if (info.prop->GetType() != DPT_String)
1642 return pContext->ThrowNativeError("SendProp %s is not a string (%d != %d)",
1644 info.prop->GetType(),
1648 offset = info.actual_offset;
1654 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1661 if (!bIsStringIndex)
1663 src = (char *)((uint8_t *)pEntity + offset);
1669 idx = *(string_t *)((uint8_t *)pEntity + offset);
1670 src = (idx == NULL_STRING) ? "" : STRING(idx);
1673 pContext->StringToLocalUTF8(params[4], params[5], src, &len);
1678 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
1680 CBaseEntity *pEntity;
1684 edict_t *pEdict = GetEntity(params[1], &pEntity);
1686 if (!pEdict || !pEntity)
1688 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
1696 typedescription_t *td;
1697 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
1699 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
1701 pContext->LocalToString(params[3], &prop);
1702 if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
1704 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
1706 if (td->fieldType != FIELD_CHARACTER)
1708 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
1710 offset = td->fieldOffset[TD_OFFSET_NORMAL];
1711 maxlen = td->fieldSize;
1717 IServerNetworkable *pNet = pEdict->GetNetworkable();
1720 return pContext->ThrowNativeError("The edict is not networkable");
1722 pContext->LocalToString(params[3], &prop);
1723 SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
1726 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
1728 if (pSend->GetType() != DPT_String)
1730 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
1732 offset = pSend->GetOffset();
1733 maxlen = DT_MAX_STRING_BUFFERSIZE;
1738 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
1743 char *dest = (char *)((uint8_t *)pEntity + offset);
1745 pContext->LocalToString(params[4], &src);
1746 size_t len = strncopy(dest, src, maxlen);
1748 if (params[2] == Prop_Send)
1750 g_HL2.SetEdictStateChanged(pEdict, offset);
1756 REGISTER_NATIVES(entityNatives)
1758 {"ChangeEdictState", ChangeEdictState},
1759 {"CreateEdict", CreateEdict},
1760 {"FindDataMapOffs", FindDataMapOffs},
1761 {"FindSendPropInfo", FindSendPropInfo},
1762 {"FindSendPropOffs", FindSendPropOffs},
1763 {"GetEdictClassname", GetEdictClassname},
1764 {"GetEdictFlags", GetEdictFlags},
1765 {"GetEntData", GetEntData},
1766 {"GetEntDataEnt", GetEntDataEnt}, /** DEPRECATED */
1767 {"GetEntDataEnt2", GetEntDataEnt2},
1768 {"GetEntDataFloat", GetEntDataFloat},
1769 {"GetEntDataString", GetEntDataString},
1770 {"GetEntDataVector", GetEntDataVector},
1771 {"GetEntProp", GetEntProp},
1772 {"GetEntPropEnt", GetEntPropEnt},
1773 {"GetEntPropFloat", GetEntPropFloat},
1774 {"GetEntPropString", GetEntPropString},
1775 {"GetEntPropVector", GetEntPropVector},
1776 {"GetEntityCount", GetEntityCount},
1777 {"GetEntityNetClass", GetEntityNetClass},
1778 {"GetMaxEntities", GetMaxEntities},
1779 {"IsEntNetworkable", IsEntNetworkable},
1780 {"IsValidEdict", IsValidEdict},
1781 {"IsValidEntity", IsValidEntity},
1782 {"RemoveEdict", RemoveEdict},
1783 {"SetEdictFlags", SetEdictFlags},
1784 {"SetEntData", SetEntData},
1785 {"SetEntDataEnt", SetEntDataEnt}, /** DEPRECATED */
1786 {"SetEntDataEnt2", SetEntDataEnt2},
1787 {"SetEntDataFloat", SetEntDataFloat},
1788 {"SetEntDataVector", SetEntDataVector},
1789 {"SetEntDataString", SetEntDataString},
1790 {"SetEntProp", SetEntProp},
1791 {"SetEntPropEnt", SetEntPropEnt},
1792 {"SetEntPropFloat", SetEntPropFloat},
1793 {"SetEntPropString", SetEntPropString},
1794 {"SetEntPropVector", SetEntPropVector},