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"
47 inline edict_t *GetEdict(cell_t num)
49 edict_t *pEdict = engine->PEntityOfEntIndex(num);
50 if (!pEdict || pEdict->IsFree())
54 if (num > 0 && num < g_Players.GetMaxClients())
56 CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
57 if (!pPlayer || !pPlayer->IsConnected())
65 inline edict_t *GetEntity(cell_t num, CBaseEntity **pData)
67 edict_t *pEdict = engine->PEntityOfEntIndex(num);
68 if (!pEdict || pEdict->IsFree())
72 if (num > 0 && num < g_Players.GetMaxClients())
74 CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
75 if (!pPlayer || !pPlayer->IsConnected())
81 if ((pUnk=pEdict->GetUnknown()) == NULL)
85 *pData = pUnk->GetBaseEntity();
90 datamap_t *VGetDataDescMap(CBaseEntity *pThisPtr, int offset)
92 void **this_ptr = *reinterpret_cast<void ***>(&pThisPtr);
93 void **vtable = *reinterpret_cast<void ***>(pThisPtr);
94 void *vfunc = vtable[offset];
98 datamap_t *(VEmptyClass::*mfpnew)();
99 #ifndef PLATFORM_POSIX
114 return (datamap_t *)(reinterpret_cast<VEmptyClass *>(this_ptr)->*u.mfpnew)();
117 inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity)
121 if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset)
126 return VGetDataDescMap(pEntity, offset);
129 /* :TODO: Move this! */
130 datamap_t *CHalfLife2::GetDataMap(CBaseEntity *pEntity)
132 return CBaseEntity_GetDataDescMap(pEntity);
135 static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params)
137 return gpGlobals->maxEntities;
140 static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params)
142 edict_t *pEdict = engine->CreateEdict();
149 return engine->IndexOfEdict(pEdict);
152 static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
154 edict_t *pEdict = engine->PEntityOfEntIndex(params[1]);
158 return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]);
161 engine->RemoveEdict(pEdict);
166 static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params)
168 edict_t *pEdict = GetEdict(params[1]);
175 /* Shouldn't be necessary... not sure though */
176 return pEdict->IsFree() ? 0 : 1;
179 static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
181 edict_t *pEdict = GetEdict(params[1]);
188 IServerUnknown *pUnknown = pEdict->GetUnknown();
194 CBaseEntity *pEntity = pUnknown->GetBaseEntity();
195 return (pEntity != NULL) ? 1 : 0;
198 static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
200 edict_t *pEdict = GetEdict(params[1]);
207 return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
210 static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
212 return engine->GetEntityCount();
215 static cell_t GetEdictFlags(IPluginContext *pContext, const cell_t *params)
217 edict_t *pEdict = GetEdict(params[1]);
221 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
224 return pEdict->m_fStateFlags;
227 static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params)
229 edict_t *pEdict = GetEdict(params[1]);
233 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
236 pEdict->m_fStateFlags = params[2];
241 static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params)
243 edict_t *pEdict = GetEdict(params[1]);
247 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
250 const char *cls = pEdict->GetClassName();
252 if (!cls || cls[0] == '\0')
257 pContext->StringToLocal(params[2], params[3], cls);
262 static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
264 edict_t *pEdict = GetEdict(params[1]);
268 return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
271 IServerNetworkable *pNet = pEdict->GetNetworkable();
277 ServerClass *pClass = pNet->GetServerClass();
279 pContext->StringToLocal(params[2], params[3], pClass->GetName());
284 static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
286 CBaseEntity *pEntity;
287 edict_t *pEdict = GetEntity(params[1], &pEntity);
289 if (!pEdict || !pEntity)
291 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
294 int offset = params[2];
295 if (offset < 0 || offset > 32768)
297 return pContext->ThrowNativeError("Offset %d is invalid", offset);
303 return *(int *)((uint8_t *)pEntity + offset);
305 return *(short *)((uint8_t *)pEntity + offset);
307 return *((uint8_t *)pEntity + offset);
309 return pContext->ThrowNativeError("Integer size %d is invalid", params[3]);
313 static cell_t SetEntData(IPluginContext *pContext, const cell_t *params)
315 CBaseEntity *pEntity;
316 edict_t *pEdict = GetEntity(params[1], &pEntity);
318 if (!pEdict || !pEntity)
320 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
323 int offset = params[2];
324 if (offset < 0 || offset > 32768)
326 return pContext->ThrowNativeError("Offset %d is invalid", offset);
331 g_HL2.SetEdictStateChanged(pEdict, offset);
338 *(int *)((uint8_t *)pEntity + offset) = params[3];
343 *(short *)((uint8_t *)pEntity + offset) = params[3];
348 *((uint8_t *)pEntity + offset) = params[3];
352 return pContext->ThrowNativeError("Integer size %d is invalid", params[4]);
358 static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
360 CBaseEntity *pEntity;
361 edict_t *pEdict = GetEntity(params[1], &pEntity);
363 if (!pEdict || !pEntity)
365 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
368 int offset = params[2];
369 if (offset < 0 || offset > 32768)
371 return pContext->ThrowNativeError("Offset %d is invalid", offset);
374 float f = *(float *)((uint8_t *)pEntity + offset);
379 static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params)
381 CBaseEntity *pEntity;
382 edict_t *pEdict = GetEntity(params[1], &pEntity);
384 if (!pEdict || !pEntity)
386 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
389 int offset = params[2];
390 if (offset < 0 || offset > 32768)
392 return pContext->ThrowNativeError("Offset %d is invalid", offset);
395 *(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
399 g_HL2.SetEdictStateChanged(pEdict, offset);
405 static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
407 CBaseEntity *pEntity;
408 edict_t *pEdict = GetEntity(params[1], &pEntity);
410 if (!pEdict || !pEntity)
412 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
415 int offset = params[2];
416 if (offset < 0 || offset > 32768)
418 return pContext->ThrowNativeError("Offset %d is invalid", offset);
421 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
424 pContext->LocalToPhysAddr(params[3], &vec);
426 vec[0] = sp_ftoc(v->x);
427 vec[1] = sp_ftoc(v->y);
428 vec[2] = sp_ftoc(v->z);
433 static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params)
435 CBaseEntity *pEntity;
436 edict_t *pEdict = GetEntity(params[1], &pEntity);
438 if (!pEdict || !pEntity)
440 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
443 int offset = params[2];
444 if (offset < 0 || offset > 32768)
446 return pContext->ThrowNativeError("Offset %d is invalid", offset);
449 Vector *v = (Vector *)((uint8_t *)pEntity + offset);
452 pContext->LocalToPhysAddr(params[3], &vec);
454 v->x = sp_ctof(vec[0]);
455 v->y = sp_ctof(vec[1]);
456 v->z = sp_ctof(vec[2]);
460 g_HL2.SetEdictStateChanged(pEdict, offset);
466 static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
468 CBaseEntity *pEntity;
469 edict_t *pEdict = GetEntity(params[1], &pEntity);
471 if (!pEdict || !pEntity)
473 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
476 int offset = params[2];
477 if (offset < 0 || offset > 32768)
479 return pContext->ThrowNativeError("Offset %d is invalid", offset);
482 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
489 /* :TODO: check serial no.? */
491 return hndl.GetEntryIndex();
494 static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
496 CBaseEntity *pEntity;
497 edict_t *pEdict = GetEntity(params[1], &pEntity);
499 if (!pEdict || !pEntity)
501 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
504 int offset = params[2];
505 if (offset < 0 || offset > 32768)
507 return pContext->ThrowNativeError("Offset %d is invalid", offset);
510 CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
516 edict_t *pEdict = GetEdict(params[3]);
519 return pContext->ThrowNativeError("Entity %d is invalid", params[3]);
521 IServerEntity *pEntOther = pEdict->GetIServerEntity();
527 g_HL2.SetEdictStateChanged(pEdict, offset);
533 static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
535 edict_t *pEdict = GetEdict(params[1]);
539 return pContext->ThrowNativeError("Edict %d is invalid", params[1]);
542 g_HL2.SetEdictStateChanged(pEdict, params[2]);
547 static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
550 pContext->LocalToString(params[1], &cls);
551 pContext->LocalToString(params[2], &prop);
553 SendProp *pSend = g_HL2.FindInSendTable(cls, prop);
560 return pSend->GetOffset();
563 static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
565 CBaseEntity *pEntity;
567 typedescription_t *td;
569 edict_t *pEdict = GetEntity(params[1], &pEntity);
571 if (!pEdict || !pEntity)
573 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
576 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
578 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
581 pContext->LocalToString(params[2], &offset);
582 if ((td=g_HL2.FindInDataMap(pMap, offset)) == NULL)
587 return td->fieldOffset[TD_OFFSET_NORMAL];
590 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
592 CBaseEntity *pEntity;
593 edict_t *pEdict = GetEntity(params[1], &pEntity);
595 if (!pEdict || !pEntity)
597 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
600 int offset = params[2];
601 if (offset < 0 || offset > 32768)
603 return pContext->ThrowNativeError("Offset %d is invalid", offset);
607 char *src = (char *)((uint8_t *)pEntity + offset);
608 pContext->StringToLocalUTF8(params[3], params[4], src, &len);
613 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
615 CBaseEntity *pEntity;
616 edict_t *pEdict = GetEntity(params[1], &pEntity);
618 if (!pEdict || !pEntity)
620 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
623 int offset = params[2];
624 if (offset < 0 || offset > 32768)
626 return pContext->ThrowNativeError("Offset %d is invalid", offset);
630 char *dest = (char *)((uint8_t *)pEntity + offset);
632 pContext->LocalToString(params[3], &src);
633 size_t len = strncopy(dest, src, params[4]);
637 g_HL2.SetEdictStateChanged(pEdict, offset);
643 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
645 CBaseEntity *pEntity;
648 edict_t *pEdict = GetEntity(params[1], &pEntity);
650 if (!pEdict || !pEntity)
652 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
660 typedescription_t *td;
661 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
663 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
665 pContext->LocalToString(params[3], &prop);
666 if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
668 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
670 if (td->fieldType != FIELD_CHARACTER)
672 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
674 offset = td->fieldOffset[TD_OFFSET_NORMAL];
680 IServerNetworkable *pNet = pEdict->GetNetworkable();
683 return pContext->ThrowNativeError("The edict is not networkable");
685 pContext->LocalToString(params[3], &prop);
686 SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
689 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
691 if (pSend->GetType() != DPT_String)
693 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
695 offset = pSend->GetOffset();
700 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
705 char *src = (char *)((uint8_t *)pEntity + offset);
706 pContext->StringToLocalUTF8(params[4], params[5], src, &len);
711 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
713 CBaseEntity *pEntity;
717 bool is_sendprop = false;
718 edict_t *pEdict = GetEntity(params[1], &pEntity);
720 if (!pEdict || !pEntity)
722 return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
730 typedescription_t *td;
731 if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
733 return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
735 pContext->LocalToString(params[3], &prop);
736 if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
738 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
740 if (td->fieldType != FIELD_CHARACTER)
742 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
744 offset = td->fieldOffset[TD_OFFSET_NORMAL];
745 maxlen = td->fieldSize;
751 IServerNetworkable *pNet = pEdict->GetNetworkable();
754 return pContext->ThrowNativeError("The edict is not networkable");
756 pContext->LocalToString(params[3], &prop);
757 SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
760 return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
762 if (pSend->GetType() != DPT_String)
764 return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
766 offset = pSend->GetOffset();
767 maxlen = DT_MAX_STRING_BUFFERSIZE;
773 return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
778 char *dest = (char *)((uint8_t *)pEntity + offset);
780 pContext->LocalToString(params[4], &src);
781 size_t len = strncopy(dest, src, maxlen);
785 g_HL2.SetEdictStateChanged(pEdict, offset);
791 REGISTER_NATIVES(entityNatives)
793 {"ChangeEdictState", ChangeEdictState},
794 {"CreateEdict", CreateEdict},
795 {"FindSendPropOffs", FindSendPropOffs},
796 {"GetEdictClassname", GetEdictClassname},
797 {"GetEdictFlags", GetEdictFlags},
798 {"GetEntData", GetEntData},
799 {"GetEntDataEnt", GetEntDataEnt},
800 {"GetEntDataFloat", GetEntDataFloat},
801 {"GetEntDataVector", GetEntDataVector},
802 {"GetEntityCount", GetEntityCount},
803 {"GetEntityNetClass", GetEntityNetClass},
804 {"GetMaxEntities", GetMaxEntities},
805 {"IsEntNetworkable", IsEntNetworkable},
806 {"IsValidEdict", IsValidEdict},
807 {"IsValidEntity", IsValidEntity},
808 {"RemoveEdict", RemoveEdict},
809 {"SetEdictFlags", SetEdictFlags},
810 {"SetEntData", SetEntData},
811 {"SetEntDataEnt", SetEntDataEnt},
812 {"SetEntDataFloat", SetEntDataFloat},
813 {"SetEntDataVector", SetEntDataVector},
814 {"FindDataMapOffs", FindDataMapOffs},
815 {"GetEntDataString", GetEntDataString},
816 {"SetEntDataString", SetEntDataString},
817 {"GetEntPropString", GetEntPropString},
818 {"SetEntPropString", SetEntPropString},