Update CS:GO team score gamedata.
3 * =============================================================================
4 * Source SDK Hooks Extension
5 * Copyright (C) 2010-2012 Nicholas Hastings
6 * Copyright (C) 2009-2010 Erik Minekus
7 * =============================================================================
9 * This program is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, version 3.0, as published by the
11 * Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
21 * As a special exception, AlliedModders LLC gives you permission to link the
22 * code of this program (as well as its derivative works) to "Half-Life 2," the
23 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
24 * by the Valve Corporation. You must obey the GNU General Public License in
25 * all respects for all other code used. Additionally, AlliedModders LLC grants
26 * this exception to all derivative works. AlliedModders LLC defines further
27 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
28 * or <http://www.sourcemod.net/license.php>.
33 #include <sourcemod_version.h>
34 #include "extension.h"
35 #include "compat_wrappers.h"
38 #include <sm_platform.h>
42 //#define SDKHOOKSDEBUG
48 // Order MUST match SDKHookType enum
49 HookTypeData g_HookTypes[SDKHook_MAXHOOKS] =
51 // Hook name DT required Supported (always false til later)
52 {"EndTouch", "", false},
53 {"FireBulletsPost", "", false},
54 {"OnTakeDamage", "", false},
55 {"OnTakeDamagePost", "", false},
56 {"PreThink", "DT_BasePlayer", false},
57 {"PostThink", "DT_BasePlayer", false},
58 {"SetTransmit", "", false},
60 {"StartTouch", "", false},
63 {"TraceAttack", "", false},
64 {"TraceAttackPost", "", false},
65 {"WeaponCanSwitchTo", "DT_BaseCombatCharacter", false},
66 {"WeaponCanUse", "DT_BaseCombatCharacter", false},
67 {"WeaponDrop", "DT_BaseCombatCharacter", false},
68 {"WeaponEquip", "DT_BaseCombatCharacter", false},
69 {"WeaponSwitch", "DT_BaseCombatCharacter", false},
70 {"ShouldCollide", "", false},
71 {"PreThinkPost", "DT_BasePlayer", false},
72 {"PostThinkPost", "DT_BasePlayer", false},
73 {"ThinkPost", "", false},
74 {"EndTouchPost", "", false},
75 {"GroundEntChangedPost", "", false},
76 {"SpawnPost", "", false},
77 {"StartTouchPost", "", false},
78 {"TouchPost", "", false},
79 {"VPhysicsUpdate", "", false},
80 {"VPhysicsUpdatePost", "", false},
81 {"WeaponCanSwitchToPost", "DT_BaseCombatCharacter", false},
82 {"WeaponCanUsePost", "DT_BaseCombatCharacter", false},
83 {"WeaponDropPost", "DT_BaseCombatCharacter", false},
84 {"WeaponEquipPost", "DT_BaseCombatCharacter", false},
85 {"WeaponSwitchPost", "DT_BaseCombatCharacter", false},
87 {"UsePost", "", false},
88 {"Reload", "DT_BaseCombatWeapon", false},
89 {"ReloadPost", "DT_BaseCombatWeapon", false},
90 {"GetMaxHealth", "", false},
94 SMEXT_LINK(&g_Interface);
96 CGlobalVars *gpGlobals;
97 ke::Vector<CVTableList *> g_HookList[SDKHook_MAXHOOKS];
99 CBitVec<NUM_ENT_ENTRIES> m_EntityExists;
101 IBinTools *g_pBinTools = NULL;
104 #if SOURCE_ENGINE >= SE_ORANGEBOX
105 IServerTools *servertools = NULL;
108 // global hooks and forwards
109 IForward *g_pOnEntityCreated = NULL;
110 IForward *g_pOnEntityDestroyed = NULL;
112 #ifdef GAMEDESC_CAN_CHANGE
113 int g_hookOnGetGameDescription = 0;
114 IForward *g_pOnGetGameNameDescription = NULL;
117 int g_hookOnGetMapEntitiesString = 0;
118 int g_hookOnLevelInit = 0;
119 IForward *g_pOnLevelInit = NULL;
121 IGameConfig *g_pGameConf = NULL;
123 char g_szMapEntities[2097152];
125 CUtlVector<IEntityListener *> *EntListeners()
127 void *gEntList = gamehelpers->GetGlobalEntityList();
130 int offset = -1; /* 65572 */
131 if (g_pGameConf->GetOffset("EntityListeners", &offset))
133 return (CUtlVector<IEntityListener *> *)((intptr_t) gEntList + offset);
139 if (g_pGameConf->GetAddress("EntityListenersPtr", &entListeners))
141 return (CUtlVector<IEntityListener *> *)entListeners;
150 * IServerGameDLL & IVEngineServer Hooks
152 SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, const char *, const char *, const char *, const char *, bool, bool);
153 #ifdef GAMEDESC_CAN_CHANGE
154 SH_DECL_HOOK0(IServerGameDLL, GetGameDescription, SH_NOATTRIB, 0, const char *);
156 SH_DECL_HOOK0(IVEngineServer, GetMapEntitiesString, SH_NOATTRIB, 0, const char *);
162 SH_DECL_MANUALHOOK1_void(EndTouch, 0, 0, 0, CBaseEntity *);
163 SH_DECL_MANUALHOOK1_void(FireBullets, 0, 0, 0, FireBulletsInfo_t const&);
164 #ifdef GETMAXHEALTH_IS_VIRTUAL
165 SH_DECL_MANUALHOOK0(GetMaxHealth, 0, 0, 0, int);
167 SH_DECL_MANUALHOOK1_void(GroundEntChanged, 0, 0, 0, void *);
168 SH_DECL_MANUALHOOK1(OnTakeDamage, 0, 0, 0, int, CTakeDamageInfoHack &);
169 SH_DECL_MANUALHOOK0_void(PreThink, 0, 0, 0);
170 SH_DECL_MANUALHOOK0_void(PostThink, 0, 0, 0);
171 SH_DECL_MANUALHOOK0(Reload, 0, 0, 0, bool);
172 SH_DECL_MANUALHOOK2_void(SetTransmit, 0, 0, 0, CCheckTransmitInfo *, bool);
173 SH_DECL_MANUALHOOK2(ShouldCollide, 0, 0, 0, bool, int, int);
174 #if SOURCE_ENGINE == SE_DOTA
175 SH_DECL_MANUALHOOK1_void(Spawn, 0, 0, 0, CEntityKeyValues *);
177 SH_DECL_MANUALHOOK0_void(Spawn, 0, 0, 0);
179 SH_DECL_MANUALHOOK1_void(StartTouch, 0, 0, 0, CBaseEntity *);
180 SH_DECL_MANUALHOOK0_void(Think, 0, 0, 0);
181 SH_DECL_MANUALHOOK1_void(Touch, 0, 0, 0, CBaseEntity *);
182 #if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013
183 SH_DECL_MANUALHOOK4_void(TraceAttack, 0, 0, 0, CTakeDamageInfoHack &, const Vector &, CGameTrace *, CDmgAccumulator *);
185 SH_DECL_MANUALHOOK3_void(TraceAttack, 0, 0, 0, CTakeDamageInfoHack &, const Vector &, CGameTrace *);
187 SH_DECL_MANUALHOOK4_void(Use, 0, 0, 0, CBaseEntity *, CBaseEntity *, USE_TYPE, float);
188 SH_DECL_MANUALHOOK1_void(VPhysicsUpdate, 0, 0, 0, IPhysicsObject *);
189 SH_DECL_MANUALHOOK1(Weapon_CanSwitchTo, 0, 0, 0, bool, CBaseCombatWeapon *);
190 SH_DECL_MANUALHOOK1(Weapon_CanUse, 0, 0, 0, bool, CBaseCombatWeapon *);
191 SH_DECL_MANUALHOOK3_void(Weapon_Drop, 0, 0, 0, CBaseCombatWeapon *, const Vector *, const Vector *);
192 SH_DECL_MANUALHOOK1_void(Weapon_Equip, 0, 0, 0, CBaseCombatWeapon *);
193 SH_DECL_MANUALHOOK2(Weapon_Switch, 0, 0, 0, bool, CBaseCombatWeapon *, int);
199 bool SDKHooks::SDK_OnLoad(char *error, size_t maxlength, bool late)
202 g_pSM->BuildPath(Path_SM, buffer, sizeof(buffer)-1, "/extensions/sdkhooks.ext." PLATFORM_LIB_EXT);
203 if (libsys->PathExists(buffer) && libsys->IsPathFile(buffer))
205 g_pSM->Format(error, maxlength-1, "SDKHooks 2.x cannot load while old version (sdkhooks.ext." PLATFORM_LIB_EXT ") is still in extensions dir");
209 g_pSM->BuildPath(Path_SM, buffer, sizeof(buffer)-1, "/gamedata/sdkhooks.games.txt");
210 if (libsys->PathExists(buffer) && libsys->IsPathFile(buffer))
212 g_pSM->Format(error, maxlength-1, "SDKHooks 2.x cannot load while old gamedata file (sdkhooks.games.txt) is still in gamedata dir");
216 sharesys->AddDependency(myself, "bintools.ext", true, true);
217 sharesys->AddNatives(myself, g_Natives);
218 sharesys->RegisterLibrary(myself, "sdkhooks");
219 sharesys->AddInterface(myself, &g_Interface);
220 sharesys->AddCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD");
221 sharesys->AddCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport");
223 playerhelpers->AddClientListener(&g_Interface);
225 plsys->AddPluginsListener(&g_Interface);
227 g_pOnEntityCreated = forwards->CreateForward("OnEntityCreated", ET_Ignore, 2, NULL, Param_Cell, Param_String);
228 g_pOnEntityDestroyed = forwards->CreateForward("OnEntityDestroyed", ET_Ignore, 1, NULL, Param_Cell);
229 #ifdef GAMEDESC_CAN_CHANGE
230 g_pOnGetGameNameDescription = forwards->CreateForward("OnGetGameDescription", ET_Hook, 2, NULL, Param_String);
232 g_pOnLevelInit = forwards->CreateForward("OnLevelInit", ET_Hook, 2, NULL, Param_String, Param_String);
235 if (!gameconfs->LoadGameConfigFile("sdkhooks.games", &g_pGameConf, buffer, sizeof(buffer)))
239 g_pSM->Format(error, maxlength, "Could not read sdkhooks.games gamedata: %s", buffer);
245 CUtlVector<IEntityListener *> *entListeners = EntListeners();
248 g_pSM->Format(error, maxlength, "Failed to setup entity listeners");
252 entListeners->AddToTail(this);
256 #if SOURCE_ENGINE >= SE_ORANGEBOX
259 for (IHandleEntity *pEnt = (IHandleEntity *)servertools->FirstEntity(); pEnt; pEnt = (IHandleEntity *)servertools->NextEntity((CBaseEntity *)pEnt))
261 hndl = pEnt->GetRefEHandle();
265 index = hndl.GetEntryIndex();
266 m_EntityExists.Set(index);
269 for (int i = 0; i < NUM_ENT_ENTRIES; i++)
271 if (gamehelpers->ReferenceToEntity(i) != NULL)
272 m_EntityExists.Set(i);
279 inline void HookLevelInit()
281 assert(g_hookOnLevelInit == 0);
282 g_hookOnLevelInit = SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(&g_Interface, &SDKHooks::Hook_LevelInit), false);
283 assert(g_hookOnGetMapEntitiesString == 0);
284 g_hookOnGetMapEntitiesString = SH_ADD_HOOK(IVEngineServer, GetMapEntitiesString, engine, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GetMapEntitiesString), false);
287 #ifdef GAMEDESC_CAN_CHANGE
288 inline void HookGetGameDescription()
290 assert(g_hookOnGetGameDescription == 0);
291 g_hookOnGetGameDescription = SH_ADD_HOOK(IServerGameDLL, GetGameDescription, gamedll, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GetGameDescription), false);
295 void SDKHooks::SDK_OnAllLoaded()
297 SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
301 g_pSM->LogError(myself, "Could not find interface: " SMINTERFACE_BINTOOLS_NAME);
305 if (g_pOnLevelInit->GetFunctionCount() > 0)
307 #ifdef GAMEDESC_CAN_CHANGE
308 if (g_pOnGetGameNameDescription->GetFunctionCount() > 0)
309 HookGetGameDescription();
313 #define KILL_HOOK_IF_ACTIVE(hook) \
316 SH_REMOVE_HOOK_ID(hook); \
319 void SDKHooks::SDK_OnUnload()
321 // Remove left over hooks
322 Unhook(reinterpret_cast<SourcePawn::IPluginContext *>(NULL));
324 KILL_HOOK_IF_ACTIVE(g_hookOnLevelInit);
325 KILL_HOOK_IF_ACTIVE(g_hookOnGetMapEntitiesString);
327 #ifdef GAMEDESC_CAN_CHANGE
328 KILL_HOOK_IF_ACTIVE(g_hookOnGetGameDescription);
331 forwards->ReleaseForward(g_pOnEntityCreated);
332 forwards->ReleaseForward(g_pOnEntityDestroyed);
333 #ifdef GAMEDESC_CAN_CHANGE
334 forwards->ReleaseForward(g_pOnGetGameNameDescription);
336 forwards->ReleaseForward(g_pOnLevelInit);
338 plsys->RemovePluginsListener(&g_Interface);
340 playerhelpers->RemoveClientListener(&g_Interface);
342 sharesys->DropCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD");
343 sharesys->DropCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport");
345 CUtlVector<IEntityListener *> *entListeners = EntListeners();
346 entListeners->FindAndRemove(this);
348 gameconfs->CloseGameConfigFile(g_pGameConf);
351 bool SDKHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
353 GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
355 #if SOURCE_ENGINE >= SE_ORANGEBOX
356 GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION);
359 CONVAR_REGISTER(this);
361 gpGlobals = ismm->GetCGlobals();
366 const char *SDKHooks::GetExtensionVerString()
368 return SOURCEMOD_VERSION;
371 const char *SDKHooks::GetExtensionDateString()
373 return SOURCEMOD_BUILD_TIME;
376 void SDKHooks::OnPluginLoaded(IPlugin *plugin)
378 if (g_pOnLevelInit->GetFunctionCount() > 0 && g_hookOnLevelInit == 0)
381 #ifdef GAMEDESC_CAN_CHANGE
382 if (g_pOnGetGameNameDescription->GetFunctionCount() > 0 && g_hookOnGetGameDescription == 0)
383 HookGetGameDescription();
387 void SDKHooks::OnPluginUnloaded(IPlugin *plugin)
389 Unhook(plugin->GetBaseContext());
391 if (g_pOnLevelInit->GetFunctionCount() == 0)
393 KILL_HOOK_IF_ACTIVE(g_hookOnLevelInit);
394 KILL_HOOK_IF_ACTIVE(g_hookOnGetMapEntitiesString);
397 #ifdef GAMEDESC_CAN_CHANGE
398 if (g_pOnGetGameNameDescription->GetFunctionCount() == 0)
399 KILL_HOOK_IF_ACTIVE(g_hookOnGetGameDescription);
403 void SDKHooks::OnClientPutInServer(int client)
405 CBaseEntity *pPlayer = gamehelpers->ReferenceToEntity(client);
407 HandleEntityCreated(pPlayer, client);
410 void SDKHooks::OnClientDisconnecting(int client)
412 CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(client);
414 HandleEntityDeleted(pEntity, client);
417 void SDKHooks::AddEntityListener(ISMEntityListener *listener)
419 m_EntListeners.push_back(listener);
422 void SDKHooks::RemoveEntityListener(ISMEntityListener *listener)
424 m_EntListeners.remove(listener);
427 bool SDKHooks::RegisterConCommandBase(ConCommandBase *pVar)
429 /* Always call META_REGCVAR instead of going through the engine. */
430 return META_REGCVAR(pVar);
433 FeatureStatus SDKHooks::GetFeatureStatus(FeatureType type, const char *name)
435 return FeatureStatus_Available;
441 cell_t SDKHooks::Call(int entity, SDKHookType type, int other)
443 return Call(gamehelpers->ReferenceToEntity(entity), type, gamehelpers->ReferenceToEntity(other));
446 cell_t SDKHooks::Call(CBaseEntity *pEnt, SDKHookType type, int other)
448 return Call(pEnt, type, gamehelpers->ReferenceToEntity(other));
451 cell_t SDKHooks::Call(CBaseEntity *pEnt, SDKHookType type, CBaseEntity *pOther)
453 cell_t ret = Pl_Continue;
455 CVTableHook vhook(pEnt);
456 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[type];
457 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
459 if (vhook != vtablehooklist[entry]->vtablehook)
464 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
465 int entity = gamehelpers->EntityToBCompatRef(pEnt);
466 int other = gamehelpers->EntityToBCompatRef(pOther);
467 for (entry = 0; entry < pawnlist.length(); ++entry)
469 if (entity != pawnlist[entry].entity)
474 IPluginFunction *callback = pawnlist[entry].callback;
475 callback->PushCell(entity);
476 callback->PushCell(other);
479 callback->Execute(&res);
492 void SDKHooks::SetupHooks()
497 // (pre is not necessarily a prehook, just named without "Post" appeneded)
499 CHECKOFFSET(EndTouch, true, true);
500 CHECKOFFSET(FireBullets, false, true);
501 CHECKOFFSET(GroundEntChanged, false, true);
502 CHECKOFFSET(OnTakeDamage, true, true);
503 CHECKOFFSET(PreThink, true, true);
504 CHECKOFFSET(PostThink, true, true);
505 CHECKOFFSET(Reload, true, true);
506 CHECKOFFSET(SetTransmit, true, false);
507 CHECKOFFSET(ShouldCollide, true, false);
508 CHECKOFFSET(Spawn, true, true);
509 CHECKOFFSET(StartTouch, true, true);
510 CHECKOFFSET(Think, true, true);
511 CHECKOFFSET(Touch, true, true);
512 CHECKOFFSET(TraceAttack, true, true);
513 CHECKOFFSET(Use, true, true);
514 CHECKOFFSET_W(CanSwitchTo, true, true);
515 CHECKOFFSET_W(CanUse, true, true);
516 CHECKOFFSET_W(Drop, true, true);
517 CHECKOFFSET_W(Equip, true, true);
518 CHECKOFFSET_W(Switch, true, true);
519 CHECKOFFSET(VPhysicsUpdate, true, true);
521 // this one is in a class all its own -_-
523 g_pGameConf->GetOffset("GroundEntChanged", &offset);
526 SH_MANUALHOOK_RECONFIGURE(GroundEntChanged, offset, 0, 0);
527 g_HookTypes[SDKHook_GroundEntChangedPost].supported = true;
530 #ifdef GETMAXHEALTH_IS_VIRTUAL
531 CHECKOFFSET(GetMaxHealth, true, false);
535 HookReturn SDKHooks::Hook(int entity, SDKHookType type, IPluginFunction *callback)
537 if(!g_HookTypes[type].supported)
538 return HookRet_NotSupported;
540 CBaseEntity *pEnt = gamehelpers->ReferenceToEntity(entity);
542 return HookRet_InvalidEntity;
543 if(type < 0 || type >= SDKHook_MAXHOOKS)
544 return HookRet_InvalidHookType;
546 if (!!strcmp(g_HookTypes[type].dtReq, ""))
548 IServerUnknown *pUnk = (IServerUnknown *)pEnt;
550 IServerNetworkable *pNet = pUnk->GetNetworkable();
551 if (pNet && !UTIL_ContainsDataTable(pNet->GetServerClass()->m_pTable, g_HookTypes[type].dtReq))
552 return HookRet_BadEntForHookType;
556 CVTableHook vhook(pEnt);
557 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[type];
558 for (entry = 0; entry < vtablehooklist.length(); ++entry)
560 if (vhook == vtablehooklist[entry]->vtablehook)
566 if (entry == vtablehooklist.length())
571 case SDKHook_EndTouch:
572 hookid = SH_ADD_MANUALVPHOOK(EndTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_EndTouch), false);
574 case SDKHook_EndTouchPost:
575 hookid = SH_ADD_MANUALVPHOOK(EndTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_EndTouchPost), true);
577 case SDKHook_FireBulletsPost:
578 hookid = SH_ADD_MANUALVPHOOK(FireBullets, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_FireBulletsPost), true);
580 #ifdef GETMAXHEALTH_IS_VIRTUAL
581 case SDKHook_GetMaxHealth:
582 hookid = SH_ADD_MANUALVPHOOK(GetMaxHealth, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GetMaxHealth), false);
585 case SDKHook_GroundEntChangedPost:
586 hookid = SH_ADD_MANUALVPHOOK(GroundEntChanged, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GroundEntChangedPost), true);
588 case SDKHook_OnTakeDamage:
589 hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamage), false);
591 case SDKHook_OnTakeDamagePost:
592 hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamagePost), true);
594 case SDKHook_PreThink:
595 hookid = SH_ADD_MANUALVPHOOK(PreThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PreThink), false);
597 case SDKHook_PreThinkPost:
598 hookid = SH_ADD_MANUALVPHOOK(PreThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PreThinkPost), true);
600 case SDKHook_PostThink:
601 hookid = SH_ADD_MANUALVPHOOK(PostThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PostThink), false);
603 case SDKHook_PostThinkPost:
604 hookid = SH_ADD_MANUALVPHOOK(PostThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PostThinkPost), true);
607 hookid = SH_ADD_MANUALVPHOOK(Reload, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Reload), false);
609 case SDKHook_ReloadPost:
610 hookid = SH_ADD_MANUALVPHOOK(Reload, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_ReloadPost), true);
612 case SDKHook_SetTransmit:
613 hookid = SH_ADD_MANUALVPHOOK(SetTransmit, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_SetTransmit), false);
616 hookid = SH_ADD_MANUALVPHOOK(Spawn, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Spawn), false);
618 case SDKHook_SpawnPost:
619 hookid = SH_ADD_MANUALVPHOOK(Spawn, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_SpawnPost), true);
621 case SDKHook_StartTouch:
622 hookid = SH_ADD_MANUALVPHOOK(StartTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_StartTouch), false);
624 case SDKHook_StartTouchPost:
625 hookid = SH_ADD_MANUALVPHOOK(StartTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_StartTouchPost), true);
628 hookid = SH_ADD_MANUALVPHOOK(Think, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Think), false);
630 case SDKHook_ThinkPost:
631 hookid = SH_ADD_MANUALVPHOOK(Think, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_ThinkPost), true);
634 hookid = SH_ADD_MANUALVPHOOK(Touch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Touch), false);
636 case SDKHook_TouchPost:
637 hookid = SH_ADD_MANUALVPHOOK(Touch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_TouchPost), true);
639 case SDKHook_TraceAttack:
640 hookid = SH_ADD_MANUALVPHOOK(TraceAttack, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_TraceAttack), false);
642 case SDKHook_TraceAttackPost:
643 hookid = SH_ADD_MANUALVPHOOK(TraceAttack, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_TraceAttackPost), true);
646 hookid = SH_ADD_MANUALVPHOOK(Use, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Use), false);
648 case SDKHook_UsePost:
649 hookid = SH_ADD_MANUALVPHOOK(Use, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_UsePost), true);
651 case SDKHook_VPhysicsUpdate:
652 hookid = SH_ADD_MANUALVPHOOK(VPhysicsUpdate, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_VPhysicsUpdate), false);
654 case SDKHook_VPhysicsUpdatePost:
655 hookid = SH_ADD_MANUALVPHOOK(VPhysicsUpdate, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_VPhysicsUpdatePost), true);
657 case SDKHook_WeaponCanSwitchTo:
658 hookid = SH_ADD_MANUALVPHOOK(Weapon_CanSwitchTo, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanSwitchTo), false);
660 case SDKHook_WeaponCanSwitchToPost:
661 hookid = SH_ADD_MANUALVPHOOK(Weapon_CanSwitchTo, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanSwitchToPost), true);
663 case SDKHook_WeaponCanUse:
664 hookid = SH_ADD_MANUALVPHOOK(Weapon_CanUse, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanUse), false);
666 case SDKHook_WeaponCanUsePost:
667 hookid = SH_ADD_MANUALVPHOOK(Weapon_CanUse, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanUsePost), true);
669 case SDKHook_WeaponDrop:
670 hookid = SH_ADD_MANUALVPHOOK(Weapon_Drop, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponDrop), false);
672 case SDKHook_WeaponDropPost:
673 hookid = SH_ADD_MANUALVPHOOK(Weapon_Drop, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponDropPost), true);
675 case SDKHook_WeaponEquip:
676 hookid = SH_ADD_MANUALVPHOOK(Weapon_Equip, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponEquip), false);
678 case SDKHook_WeaponEquipPost:
679 hookid = SH_ADD_MANUALVPHOOK(Weapon_Equip, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponEquipPost), true);
681 case SDKHook_WeaponSwitch:
682 hookid = SH_ADD_MANUALVPHOOK(Weapon_Switch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponSwitch), false);
684 case SDKHook_WeaponSwitchPost:
685 hookid = SH_ADD_MANUALVPHOOK(Weapon_Switch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponSwitchPost), true);
687 case SDKHook_ShouldCollide:
688 hookid = SH_ADD_MANUALVPHOOK(ShouldCollide, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_ShouldCollide), false);
692 vhook.SetHookID(hookid);
694 CVTableList *vtablelist = new CVTableList;
695 vtablelist->vtablehook = new CVTableHook(vhook);
696 vtablehooklist.append(vtablelist);
699 // Add hook to hook list
701 hook.entity = gamehelpers->EntityToBCompatRef(pEnt);
702 hook.callback = callback;
703 vtablehooklist[entry]->hooks.append(hook);
705 return HookRet_Successful;
708 void SDKHooks::Unhook(CBaseEntity *pEntity)
715 int entity = gamehelpers->EntityToBCompatRef(pEntity);
716 for (size_t type = 0; type < SDKHook_MAXHOOKS; ++type)
718 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[type];
719 for (size_t listentry = 0; listentry < vtablehooklist.length(); ++listentry)
721 ke::Vector<HookList> &pawnhooks = vtablehooklist[listentry]->hooks;
722 for (size_t entry = 0; entry < pawnhooks.length(); ++entry)
724 if (entity != pawnhooks[entry].entity)
729 pawnhooks.remove(entry--);
732 if (pawnhooks.length() == 0)
734 delete vtablehooklist[listentry];
735 vtablehooklist.remove(listentry--);
741 void SDKHooks::Unhook(IPluginContext *pContext)
743 for (size_t type = 0; type < SDKHook_MAXHOOKS; ++type)
745 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[type];
746 for (size_t listentry = 0; listentry < vtablehooklist.length(); ++listentry)
748 ke::Vector<HookList> &pawnhooks = vtablehooklist[listentry]->hooks;
749 for (size_t entry = 0; entry < pawnhooks.length(); ++entry)
751 if (pContext != NULL && pContext != pawnhooks[entry].callback->GetParentRuntime()->GetDefaultContext())
756 pawnhooks.remove(entry--);
759 if (pawnhooks.length() == 0)
761 delete vtablehooklist[listentry];
762 vtablehooklist.remove(listentry--);
768 void SDKHooks::Unhook(int entity, SDKHookType type, IPluginFunction *pCallback)
770 CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(entity);
776 CVTableHook vhook(pEntity);
777 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[type];
778 for (size_t listentry = 0; listentry < vtablehooklist.length(); ++listentry)
780 if (vhook != vtablehooklist[listentry]->vtablehook)
785 entity = gamehelpers->EntityToBCompatRef(pEntity);
787 ke::Vector<HookList> &pawnhooks = vtablehooklist[listentry]->hooks;
788 for (size_t entry = 0; entry < pawnhooks.length(); ++entry)
790 HookList &hookentry = pawnhooks[entry];
791 if (entity != hookentry.entity || pCallback != hookentry.callback)
796 pawnhooks.remove(entry--);
799 if (pawnhooks.length() == 0)
801 delete vtablehooklist[listentry];
802 vtablehooklist.remove(listentry);
810 * IEntityFactoryDictionary, IServerGameDLL & IVEngineServer Hook Handlers
812 void SDKHooks::OnEntityCreated(CBaseEntity *pEntity)
814 // Call OnEntityCreated forward
815 int ref = gamehelpers->EntityToBCompatRef(pEntity);
816 int index = gamehelpers->ReferenceToIndex(ref);
818 // This can be -1 for player ents before any players have connected
819 if ((unsigned)index == INVALID_EHANDLE_INDEX || m_EntityExists.IsBitSet(index) || (index > 0 && index <= playerhelpers->GetMaxClients()))
824 HandleEntityCreated(pEntity, ref);
827 #ifdef GAMEDESC_CAN_CHANGE
828 const char *SDKHooks::Hook_GetGameDescription()
830 static char szGameDesc[64];
831 cell_t result = Pl_Continue;
833 g_pSM->Format(szGameDesc, sizeof(szGameDesc), "%s",
834 SH_CALL(gamedll, &IServerGameDLL::GetGameDescription)());
836 // Call OnGetGameDescription forward
837 g_pOnGetGameNameDescription->PushStringEx(szGameDesc, sizeof(szGameDesc), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
838 g_pOnGetGameNameDescription->Execute(&result);
840 if(result == Pl_Changed)
841 RETURN_META_VALUE(MRES_SUPERCEDE, szGameDesc);
843 RETURN_META_VALUE(MRES_IGNORED, NULL);
847 const char *SDKHooks::Hook_GetMapEntitiesString()
849 if(g_szMapEntities[0])
850 RETURN_META_VALUE(MRES_SUPERCEDE, g_szMapEntities);
852 RETURN_META_VALUE(MRES_IGNORED, NULL);
855 bool SDKHooks::Hook_LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
857 strcpy(g_szMapEntities, pMapEntities);
858 cell_t result = Pl_Continue;
860 // Call OnLevelInit forward
861 g_pOnLevelInit->PushString(pMapName);
862 g_pOnLevelInit->PushStringEx(g_szMapEntities, sizeof(g_szMapEntities), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
863 g_pOnLevelInit->Execute(&result);
865 if(result >= Pl_Handled)
866 RETURN_META_VALUE(MRES_SUPERCEDE, false);
868 if(result == Pl_Changed)
869 RETURN_META_VALUE_NEWPARAMS(MRES_HANDLED, true, &IServerGameDLL::LevelInit, (pMapName, g_szMapEntities, pOldLevel, pLandmarkName, loadGame, background));
871 RETURN_META_VALUE(MRES_IGNORED, true);
876 * CBaseEntity Hook Handlers
878 void SDKHooks::Hook_EndTouch(CBaseEntity *pOther)
880 cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_EndTouch, pOther);
881 if(result >= Pl_Handled)
882 RETURN_META(MRES_SUPERCEDE);
884 RETURN_META(MRES_IGNORED);
887 void SDKHooks::Hook_EndTouchPost(CBaseEntity *pOther)
889 Call(META_IFACEPTR(CBaseEntity), SDKHook_EndTouchPost, pOther);
890 RETURN_META(MRES_IGNORED);
893 void SDKHooks::Hook_FireBulletsPost(const FireBulletsInfo_t &info)
895 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
896 int entity = gamehelpers->EntityToBCompatRef(pEntity);
898 IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(entity);
900 RETURN_META(MRES_IGNORED);
902 IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
904 RETURN_META(MRES_IGNORED);
906 CVTableHook vhook(pEntity);
907 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_FireBulletsPost];
908 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
910 if (vhook != vtablehooklist[entry]->vtablehook)
915 const char *weapon = pInfo->GetWeaponName();
917 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
918 for (entry = 0; entry < pawnlist.length(); ++entry)
920 if (entity != pawnlist[entry].entity)
925 IPluginFunction *callback = pawnlist[entry].callback;
926 callback->PushCell(entity);
927 callback->PushCell(info.m_iShots);
928 callback->PushString(weapon?weapon:"");
929 callback->Execute(NULL);
935 RETURN_META(MRES_IGNORED);
938 #ifdef GETMAXHEALTH_IS_VIRTUAL
939 int SDKHooks::Hook_GetMaxHealth()
941 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
942 int original_max = SH_MCALL(pEntity, GetMaxHealth)();
944 CVTableHook vhook(pEntity);
945 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_GetMaxHealth];
946 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
948 if (vhook != vtablehooklist[entry]->vtablehook)
953 int entity = gamehelpers->EntityToBCompatRef(pEntity);
955 int new_max = original_max;
957 cell_t res = Pl_Continue;
959 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
960 for (entry = 0; entry < pawnlist.length(); ++entry)
962 if (entity != pawnlist[entry].entity)
967 IPluginFunction *callback = pawnlist[entry].callback;
968 callback->PushCell(entity);
969 callback->PushCellByRef(&new_max);
970 callback->Execute(&res);
973 if (res >= Pl_Changed)
974 RETURN_META_VALUE(MRES_SUPERCEDE, new_max);
979 RETURN_META_VALUE(MRES_IGNORED, original_max);
983 void SDKHooks::Hook_GroundEntChangedPost(void *pVar)
985 Call(META_IFACEPTR(CBaseEntity), SDKHook_GroundEntChangedPost);
988 int SDKHooks::Hook_OnTakeDamage(CTakeDamageInfoHack &info)
990 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
992 CVTableHook vhook(pEntity);
993 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_OnTakeDamage];
994 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
996 if (vhook != vtablehooklist[entry]->vtablehook)
1001 int entity = gamehelpers->EntityToBCompatRef(pEntity);
1002 int attacker = info.GetAttacker();
1003 int inflictor = info.GetInflictor();
1004 float damage = info.GetDamage();
1005 int damagetype = info.GetDamageType();
1006 int weapon = info.GetWeapon();
1008 Vector force = info.GetDamageForce();
1009 cell_t damageForce[3] = {sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z)};
1011 Vector pos = info.GetDamagePosition();
1012 cell_t damagePosition[3] = {sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z)};
1014 cell_t res, ret = Pl_Continue;
1016 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
1017 for (entry = 0; entry < pawnlist.length(); ++entry)
1019 if (entity != pawnlist[entry].entity)
1024 IPluginFunction *callback = pawnlist[entry].callback;
1025 callback->PushCell(entity);
1026 callback->PushCellByRef(&attacker);
1027 callback->PushCellByRef(&inflictor);
1028 callback->PushFloatByRef(&damage);
1029 callback->PushCellByRef(&damagetype);
1030 callback->PushCellByRef(&weapon);
1031 callback->PushArray(damageForce, 3, SM_PARAM_COPYBACK);
1032 callback->PushArray(damagePosition, 3, SM_PARAM_COPYBACK);
1033 callback->PushCell(info.GetDamageCustom());
1034 callback->Execute(&res);
1039 if(ret == Pl_Changed)
1041 CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker);
1044 callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("Entity %d for attacker is invalid", attacker);
1045 RETURN_META_VALUE(MRES_IGNORED, 0);
1047 CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor);
1050 callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("Entity %d for inflictor is invalid", inflictor);
1051 RETURN_META_VALUE(MRES_IGNORED, 0);
1054 info.SetAttacker(pEntAttacker);
1055 info.SetInflictor(pEntInflictor);
1056 info.SetDamage(damage);
1057 info.SetDamageType(damagetype);
1058 info.SetWeapon(gamehelpers->ReferenceToEntity(weapon));
1059 info.SetDamageForce(
1060 sp_ctof(damageForce[0]),
1061 sp_ctof(damageForce[1]),
1062 sp_ctof(damageForce[2]));
1063 info.SetDamagePosition(
1064 sp_ctof(damagePosition[0]),
1065 sp_ctof(damagePosition[1]),
1066 sp_ctof(damagePosition[2]));
1071 if(ret >= Pl_Handled)
1072 RETURN_META_VALUE(MRES_SUPERCEDE, 1);
1074 if(ret == Pl_Changed)
1075 RETURN_META_VALUE(MRES_HANDLED, 1);
1080 RETURN_META_VALUE(MRES_IGNORED, 0);
1083 int SDKHooks::Hook_OnTakeDamagePost(CTakeDamageInfoHack &info)
1085 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
1087 CVTableHook vhook(pEntity);
1088 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_OnTakeDamagePost];
1089 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
1091 if (vhook != vtablehooklist[entry]->vtablehook)
1096 int entity = gamehelpers->EntityToBCompatRef(pEntity);
1098 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
1099 for (entry = 0; entry < pawnlist.length(); ++entry)
1101 if (entity != pawnlist[entry].entity)
1106 IPluginFunction *callback = pawnlist[entry].callback;
1107 callback->PushCell(entity);
1108 callback->PushCell(info.GetAttacker());
1109 callback->PushCell(info.GetInflictor());
1110 callback->PushFloat(info.GetDamage());
1111 callback->PushCell(info.GetDamageType());
1112 callback->PushCell(info.GetWeapon());
1114 Vector force = info.GetDamageForce();
1115 cell_t damageForce[3] = {sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z)};
1116 callback->PushArray(damageForce, 3);
1118 Vector pos = info.GetDamagePosition();
1119 cell_t damagePosition[3] = {sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z)};
1120 callback->PushArray(damagePosition, 3);
1122 callback->PushCell(info.GetDamageCustom());
1124 callback->Execute(NULL);
1130 RETURN_META_VALUE(MRES_IGNORED, 0);
1133 void SDKHooks::Hook_PreThink()
1135 Call(META_IFACEPTR(CBaseEntity), SDKHook_PreThink);
1136 RETURN_META(MRES_IGNORED);
1139 void SDKHooks::Hook_PreThinkPost()
1141 Call(META_IFACEPTR(CBaseEntity), SDKHook_PreThinkPost);
1144 void SDKHooks::Hook_PostThink()
1146 Call(META_IFACEPTR(CBaseEntity), SDKHook_PostThink);
1147 RETURN_META(MRES_IGNORED);
1150 void SDKHooks::Hook_PostThinkPost()
1152 Call(META_IFACEPTR(CBaseEntity), SDKHook_PostThinkPost);
1155 bool SDKHooks::Hook_Reload()
1157 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
1159 CVTableHook vhook(pEntity);
1160 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_Reload];
1161 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
1163 if (vhook != vtablehooklist[entry]->vtablehook)
1168 int entity = gamehelpers->EntityToBCompatRef(pEntity);
1169 cell_t res = Pl_Continue;
1171 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
1172 for (entry = 0; entry < pawnlist.length(); ++entry)
1174 if (entity != pawnlist[entry].entity)
1179 IPluginFunction *callback = pawnlist[entry].callback;
1180 callback->PushCell(entity);
1181 callback->Execute(&res);
1184 if (res >= Pl_Handled)
1185 RETURN_META_VALUE(MRES_SUPERCEDE, false);
1190 RETURN_META_VALUE(MRES_IGNORED, true);
1193 bool SDKHooks::Hook_ReloadPost()
1195 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
1197 CVTableHook vhook(pEntity);
1198 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_Reload];
1199 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
1201 if (vhook != vtablehooklist[entry]->vtablehook)
1206 int entity = gamehelpers->EntityToBCompatRef(pEntity);
1207 cell_t origreturn = META_RESULT_ORIG_RET(bool) ? 1 : 0;
1209 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
1210 for (entry = 0; entry < pawnlist.length(); ++entry)
1212 if (entity != pawnlist[entry].entity)
1217 IPluginFunction *callback = pawnlist[entry].callback;
1218 callback->PushCell(entity);
1219 callback->PushCell(origreturn);
1220 callback->Execute(NULL);
1229 void SDKHooks::Hook_SetTransmit(CCheckTransmitInfo *pInfo, bool bAlways)
1231 cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_SetTransmit, gamehelpers->IndexOfEdict(pInfo->m_pClientEnt));
1233 if(result >= Pl_Handled)
1234 RETURN_META(MRES_SUPERCEDE);
1236 RETURN_META(MRES_IGNORED);
1239 bool SDKHooks::Hook_ShouldCollide(int collisionGroup, int contentsMask)
1241 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
1243 CVTableHook vhook(pEntity);
1244 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_ShouldCollide];
1245 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
1247 if (vhook != vtablehooklist[entry]->vtablehook)
1252 int entity = gamehelpers->EntityToBCompatRef(pEntity);
1253 cell_t origRet = ((META_RESULT_STATUS >= MRES_OVERRIDE)?(META_RESULT_OVERRIDE_RET(bool)):(META_RESULT_ORIG_RET(bool))) ? 1 : 0;
1256 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
1257 for (entry = 0; entry < pawnlist.length(); ++entry)
1259 if (entity != pawnlist[entry].entity)
1264 IPluginFunction *callback = pawnlist[entry].callback;
1265 callback->PushCell(entity);
1266 callback->PushCell(collisionGroup);
1267 callback->PushCell(contentsMask);
1268 callback->PushCell(origRet);
1269 callback->Execute(&res);
1278 RETURN_META_VALUE(MRES_SUPERCEDE, ret);
1281 RETURN_META_VALUE(MRES_IGNORED, true);
1284 #if SOURCE_ENGINE == SE_DOTA
1285 void SDKHooks::Hook_Spawn(CEntityKeyValues *kv)
1287 void SDKHooks::Hook_Spawn()
1290 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
1292 CVTableHook vhook(pEntity);
1293 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_Spawn];
1294 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
1296 if (vhook != vtablehooklist[entry]->vtablehook)
1301 int entity = gamehelpers->EntityToBCompatRef(pEntity);
1302 cell_t res = Pl_Continue;
1304 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
1305 for (entry = 0; entry < pawnlist.length(); ++entry)
1307 if (entity != pawnlist[entry].entity)
1312 IPluginFunction *callback = pawnlist[entry].callback;
1313 callback->PushCell(entity);
1314 callback->Execute(&res);
1317 if (res >= Pl_Handled)
1318 RETURN_META(MRES_SUPERCEDE);
1323 RETURN_META(MRES_IGNORED);
1326 #if SOURCE_ENGINE == SE_DOTA
1327 void SDKHooks::Hook_SpawnPost(CEntityKeyValues *kv)
1329 void SDKHooks::Hook_SpawnPost()
1332 Call(META_IFACEPTR(CBaseEntity), SDKHook_SpawnPost);
1335 void SDKHooks::Hook_StartTouch(CBaseEntity *pOther)
1337 cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_StartTouch, pOther);
1338 if(result >= Pl_Handled)
1339 RETURN_META(MRES_SUPERCEDE);
1341 RETURN_META(MRES_IGNORED);
1344 void SDKHooks::Hook_StartTouchPost(CBaseEntity *pOther)
1346 Call(META_IFACEPTR(CBaseEntity), SDKHook_StartTouchPost, pOther);
1347 RETURN_META(MRES_IGNORED);
1350 void SDKHooks::Hook_Think()
1352 Call(META_IFACEPTR(CBaseEntity), SDKHook_Think);
1353 RETURN_META(MRES_IGNORED);
1356 void SDKHooks::Hook_ThinkPost()
1358 Call(META_IFACEPTR(CBaseEntity), SDKHook_ThinkPost);
1361 void SDKHooks::Hook_Touch(CBaseEntity *pOther)
1363 cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_Touch, pOther);
1365 if(result >= Pl_Handled)
1366 RETURN_META(MRES_SUPERCEDE);
1368 RETURN_META(MRES_IGNORED);
1371 void SDKHooks::Hook_TouchPost(CBaseEntity *pOther)
1373 Call(META_IFACEPTR(CBaseEntity), SDKHook_TouchPost, pOther);
1374 RETURN_META(MRES_IGNORED);
1377 #if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013
1378 void SDKHooks::Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator)
1380 void SDKHooks::Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr)
1383 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
1385 CVTableHook vhook(pEntity);
1386 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_TraceAttack];
1387 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
1389 if (vhook != vtablehooklist[entry]->vtablehook)
1394 int entity = gamehelpers->EntityToBCompatRef(pEntity);
1395 int attacker = info.GetAttacker();
1396 int inflictor = info.GetInflictor();
1397 float damage = info.GetDamage();
1398 int damagetype = info.GetDamageType();
1399 int ammotype = info.GetAmmoType();
1400 cell_t res, ret = Pl_Continue;
1402 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
1403 for (entry = 0; entry < pawnlist.length(); ++entry)
1405 if (entity != pawnlist[entry].entity)
1410 IPluginFunction *callback = pawnlist[entry].callback;
1411 callback->PushCell(entity);
1412 callback->PushCellByRef(&attacker);
1413 callback->PushCellByRef(&inflictor);
1414 callback->PushFloatByRef(&damage);
1415 callback->PushCellByRef(&damagetype);
1416 callback->PushCellByRef(&ammotype);
1417 callback->PushCell(ptr->hitbox);
1418 callback->PushCell(ptr->hitgroup);
1419 callback->Execute(&res);
1425 if(ret == Pl_Changed)
1427 CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker);
1430 callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("Entity %d for attacker is invalid", attacker);
1431 RETURN_META(MRES_IGNORED);
1433 CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor);
1436 callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("Entity %d for inflictor is invalid", inflictor);
1437 RETURN_META(MRES_IGNORED);
1440 info.SetAttacker(pEntAttacker);
1441 info.SetInflictor(pEntInflictor);
1442 info.SetDamage(damage);
1443 info.SetDamageType(damagetype);
1444 info.SetAmmoType(ammotype);
1449 if(ret >= Pl_Handled)
1450 RETURN_META(MRES_SUPERCEDE);
1452 if(ret == Pl_Changed)
1453 RETURN_META(MRES_HANDLED);
1458 RETURN_META(MRES_IGNORED);
1461 #if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013
1462 void SDKHooks::Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator)
1464 void SDKHooks::Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr)
1467 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
1469 CVTableHook vhook(pEntity);
1470 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_TraceAttackPost];
1471 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
1473 if (vhook != vtablehooklist[entry]->vtablehook)
1478 int entity = gamehelpers->EntityToBCompatRef(pEntity);
1480 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
1481 for (entry = 0; entry < pawnlist.length(); ++entry)
1483 if (entity != pawnlist[entry].entity)
1488 IPluginFunction *callback = pawnlist[entry].callback;
1489 callback->PushCell(entity);
1490 callback->PushCell(info.GetAttacker());
1491 callback->PushCell(info.GetInflictor());
1492 callback->PushFloat(info.GetDamage());
1493 callback->PushCell(info.GetDamageType());
1494 callback->PushCell(info.GetAmmoType());
1495 callback->PushCell(ptr->hitbox);
1496 callback->PushCell(ptr->hitgroup);
1497 callback->Execute(NULL);
1503 RETURN_META(MRES_IGNORED);
1506 void SDKHooks::Hook_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
1508 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
1510 CVTableHook vhook(pEntity);
1511 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_Use];
1512 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
1514 if (vhook != vtablehooklist[entry]->vtablehook)
1519 int entity = gamehelpers->EntityToBCompatRef(pEntity);
1520 int activator = gamehelpers->EntityToBCompatRef(pActivator);
1521 int caller = gamehelpers->EntityToBCompatRef(pCaller);
1522 cell_t ret = Pl_Continue;
1524 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
1525 for (entry = 0; entry < pawnlist.length(); ++entry)
1527 if (entity != pawnlist[entry].entity)
1532 IPluginFunction *callback = pawnlist[entry].callback;
1533 callback->PushCell(entity);
1534 callback->PushCell(activator);
1535 callback->PushCell(caller);
1536 callback->PushCell(useType);
1537 callback->PushFloat(value);
1538 callback->Execute(&ret);
1541 if (ret >= Pl_Handled)
1542 RETURN_META(MRES_SUPERCEDE);
1547 RETURN_META(MRES_IGNORED);
1550 void SDKHooks::Hook_UsePost(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
1552 CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
1554 CVTableHook vhook(pEntity);
1555 ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_UsePost];
1556 for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
1558 if (vhook != vtablehooklist[entry]->vtablehook)
1563 int entity = gamehelpers->EntityToBCompatRef(pEntity);
1564 int activator = gamehelpers->EntityToBCompatRef(pActivator);
1565 int caller = gamehelpers->EntityToBCompatRef(pCaller);
1567 ke::Vector<HookList> &pawnlist = vtablehooklist[entry]->hooks;
1568 for (entry = 0; entry < pawnlist.length(); ++entry)
1570 if (entity != pawnlist[entry].entity)
1575 IPluginFunction *callback = pawnlist[entry].callback;
1576 callback->PushCell(entity);
1577 callback->PushCell(activator);
1578 callback->PushCell(caller);
1579 callback->PushCell(useType);
1580 callback->PushFloat(value);
1581 callback->Execute(NULL);
1587 RETURN_META(MRES_IGNORED);
1590 void SDKHooks::OnEntityDeleted(CBaseEntity *pEntity)
1592 int ref = gamehelpers->EntityToBCompatRef(pEntity);
1593 int index = gamehelpers->ReferenceToIndex(ref);
1595 // This can be -1 for player ents before any players have connected
1596 if ((unsigned)index == INVALID_EHANDLE_INDEX || (index > 0 && index <= playerhelpers->GetMaxClients()))
1601 HandleEntityDeleted(pEntity, ref);
1604 void SDKHooks::Hook_VPhysicsUpdate(IPhysicsObject *pPhysics)
1606 Call(META_IFACEPTR(CBaseEntity), SDKHook_VPhysicsUpdate);
1607 RETURN_META(MRES_IGNORED);
1610 void SDKHooks::Hook_VPhysicsUpdatePost(IPhysicsObject *pPhysics)
1612 Call(META_IFACEPTR(CBaseEntity), SDKHook_VPhysicsUpdatePost);
1615 bool SDKHooks::Hook_WeaponCanSwitchTo(CBaseCombatWeapon *pWeapon)
1617 cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanSwitchTo, pWeapon);
1619 if(result >= Pl_Handled)
1620 RETURN_META_VALUE(MRES_SUPERCEDE, false);
1622 RETURN_META_VALUE(MRES_IGNORED, true);
1625 bool SDKHooks::Hook_WeaponCanSwitchToPost(CBaseCombatWeapon *pWeapon)
1627 Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanSwitchToPost, pWeapon);
1628 RETURN_META_VALUE(MRES_IGNORED, true);
1631 bool SDKHooks::Hook_WeaponCanUse(CBaseCombatWeapon *pWeapon)
1633 cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanUse, pWeapon);
1635 if(result >= Pl_Handled)
1636 RETURN_META_VALUE(MRES_SUPERCEDE, false);
1638 RETURN_META_VALUE(MRES_IGNORED, true);
1641 bool SDKHooks::Hook_WeaponCanUsePost(CBaseCombatWeapon *pWeapon)
1643 Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanUsePost, pWeapon);
1644 RETURN_META_VALUE(MRES_IGNORED, true);
1647 void SDKHooks::Hook_WeaponDrop(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity)
1649 cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponDrop, pWeapon);
1651 if(result >= Pl_Handled)
1652 RETURN_META(MRES_SUPERCEDE);
1654 RETURN_META(MRES_IGNORED);
1657 void SDKHooks::Hook_WeaponDropPost(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity)
1659 Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponDropPost, pWeapon);
1660 RETURN_META(MRES_IGNORED);
1663 void SDKHooks::Hook_WeaponEquip(CBaseCombatWeapon *pWeapon)
1665 cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponEquip, pWeapon);
1667 if(result >= Pl_Handled)
1668 RETURN_META(MRES_SUPERCEDE);
1670 RETURN_META(MRES_IGNORED);
1673 void SDKHooks::Hook_WeaponEquipPost(CBaseCombatWeapon *pWeapon)
1675 Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponEquipPost, pWeapon);
1676 RETURN_META(MRES_IGNORED);
1679 bool SDKHooks::Hook_WeaponSwitch(CBaseCombatWeapon *pWeapon, int viewmodelindex)
1681 cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponSwitch, pWeapon);
1683 if(result >= Pl_Handled)
1684 RETURN_META_VALUE(MRES_SUPERCEDE, false);
1686 RETURN_META_VALUE(MRES_IGNORED, true);
1689 bool SDKHooks::Hook_WeaponSwitchPost(CBaseCombatWeapon *pWeapon, int viewmodelindex)
1691 cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponSwitchPost, pWeapon);
1692 RETURN_META_VALUE(MRES_IGNORED, true);
1695 void SDKHooks::HandleEntityCreated(CBaseEntity *pEntity, int ref)
1697 const char *pName = gamehelpers->GetEntityClassname(pEntity);
1699 // Send OnEntityCreated to SM listeners
1700 SourceHook::List<ISMEntityListener *>::iterator iter;
1701 ISMEntityListener *pListener = NULL;
1702 for (iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++)
1704 pListener = (*iter);
1705 pListener->OnEntityCreated(pEntity, pName ? pName : "");
1708 // Call OnEntityCreated forward
1709 g_pOnEntityCreated->PushCell(ref);
1710 g_pOnEntityCreated->PushString(pName ? pName : "");
1711 g_pOnEntityCreated->Execute(NULL);
1713 m_EntityExists.Set(gamehelpers->ReferenceToIndex(ref));
1716 void SDKHooks::HandleEntityDeleted(CBaseEntity *pEntity, int ref)
1718 // Send OnEntityDestroyed to SM listeners
1719 SourceHook::List<ISMEntityListener *>::iterator iter;
1720 ISMEntityListener *pListener = NULL;
1721 for (iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++)
1723 pListener = (*iter);
1724 pListener->OnEntityDestroyed(pEntity);
1727 // Call OnEntityDestroyed forward
1728 g_pOnEntityDestroyed->PushCell(ref);
1729 g_pOnEntityDestroyed->Execute(NULL);
1733 m_EntityExists.Set(gamehelpers->ReferenceToIndex(ref), false);