diff --git a/extensions/sdkhooks/extension.cpp b/extensions/sdkhooks/extension.cpp
index 85a1de9d..d36f82d8 100644
--- a/extensions/sdkhooks/extension.cpp
+++ b/extensions/sdkhooks/extension.cpp
@@ -1,1811 +1,1811 @@
-/**
- * vim: set ts=4 :
- * =============================================================================
- * Source SDK Hooks Extension
- * Copyright (C) 2010-2012 Nicholas Hastings
- * Copyright (C) 2009-2010 Erik Minekus
- * =============================================================================
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, version 3.0, as published by the
- * Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see .
- *
- * As a special exception, AlliedModders LLC gives you permission to link the
- * code of this program (as well as its derivative works) to "Half-Life 2," the
- * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
- * by the Valve Corporation. You must obey the GNU General Public License in
- * all respects for all other code used. Additionally, AlliedModders LLC grants
- * this exception to all derivative works. AlliedModders LLC defines further
- * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
- * or .
- *
- * Version: $Id$
- */
-
-#include
-#include "extension.h"
-#include "compat_wrappers.h"
-#include "macros.h"
-#include "natives.h"
-#include
-#include
-
-
-//#define SDKHOOKSDEBUG
-
-/**
- * Globals
- */
-
-// Order MUST match SDKHookType enum
-HookTypeData g_HookTypes[SDKHook_MAXHOOKS] =
-{
-// Hook name DT required Supported (always false til later)
- {"EndTouch", "", false},
- {"FireBulletsPost", "", false},
- {"OnTakeDamage", "", false},
- {"OnTakeDamagePost", "", false},
- {"PreThink", "DT_BasePlayer", false},
- {"PostThink", "DT_BasePlayer", false},
- {"SetTransmit", "", false},
- {"Spawn", "", false},
- {"StartTouch", "", false},
- {"Think", "", false},
- {"Touch", "", false},
- {"TraceAttack", "", false},
- {"TraceAttackPost", "", false},
- {"WeaponCanSwitchTo", "DT_BaseCombatCharacter", false},
- {"WeaponCanUse", "DT_BaseCombatCharacter", false},
- {"WeaponDrop", "DT_BaseCombatCharacter", false},
- {"WeaponEquip", "DT_BaseCombatCharacter", false},
- {"WeaponSwitch", "DT_BaseCombatCharacter", false},
- {"ShouldCollide", "", false},
- {"PreThinkPost", "DT_BasePlayer", false},
- {"PostThinkPost", "DT_BasePlayer", false},
- {"ThinkPost", "", false},
- {"EndTouchPost", "", false},
- {"GroundEntChangedPost", "", false},
- {"SpawnPost", "", false},
- {"StartTouchPost", "", false},
- {"TouchPost", "", false},
- {"VPhysicsUpdate", "", false},
- {"VPhysicsUpdatePost", "", false},
- {"WeaponCanSwitchToPost", "DT_BaseCombatCharacter", false},
- {"WeaponCanUsePost", "DT_BaseCombatCharacter", false},
- {"WeaponDropPost", "DT_BaseCombatCharacter", false},
- {"WeaponEquipPost", "DT_BaseCombatCharacter", false},
- {"WeaponSwitchPost", "DT_BaseCombatCharacter", false},
- {"Use", "", false},
- {"UsePost", "", false},
- {"Reload", "DT_BaseCombatWeapon", false},
- {"ReloadPost", "DT_BaseCombatWeapon", false},
- {"GetMaxHealth", "", false},
- {"Blocked", "", false},
- {"BlockedPost", "", false},
- {"OnTakeDamageAlive", "DT_BaseCombatCharacter", false},
- {"OnTakeDamageAlivePost", "DT_BaseCombatCharacter", false},
-
- // There is no DT for CBaseMultiplayerPlayer. Going up a level
- {"CanBeAutobalanced", "DT_BasePlayer", false},
-};
-
-SDKHooks g_Interface;
-SMEXT_LINK(&g_Interface);
-
-CGlobalVars *gpGlobals;
-ke::Vector g_HookList[SDKHook_MAXHOOKS];
-
-IBinTools *g_pBinTools = NULL;
-ICvar *icvar = NULL;
-
-#if SOURCE_ENGINE >= SE_ORANGEBOX
-IServerTools *servertools = NULL;
-#endif
-
-// global hooks and forwards
-IForward *g_pOnEntityCreated = NULL;
-IForward *g_pOnEntityDestroyed = NULL;
-
-#ifdef GAMEDESC_CAN_CHANGE
-int g_hookOnGetGameDescription = 0;
-IForward *g_pOnGetGameNameDescription = NULL;
-#endif
-
-int g_hookOnGetMapEntitiesString = 0;
-int g_hookOnLevelInit = 0;
-IForward *g_pOnLevelInit = NULL;
-
-IGameConfig *g_pGameConf = NULL;
-
-char g_szMapEntities[2097152];
-
-CUtlVector *EntListeners()
-{
- void *gEntList = gamehelpers->GetGlobalEntityList();
- if (gEntList)
- {
- int offset = -1; /* 65572 */
- if (g_pGameConf->GetOffset("EntityListeners", &offset))
- {
- return (CUtlVector *)((intptr_t) gEntList + offset);
- }
- }
- else
- {
- void *entListeners;
- if (g_pGameConf->GetAddress("EntityListenersPtr", &entListeners))
- {
- return (CUtlVector *)entListeners;
- }
- }
-
- return NULL;
-}
-
-
-/**
- * IServerGameDLL & IVEngineServer Hooks
- */
-SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, const char *, const char *, const char *, const char *, bool, bool);
-#ifdef GAMEDESC_CAN_CHANGE
-SH_DECL_HOOK0(IServerGameDLL, GetGameDescription, SH_NOATTRIB, 0, const char *);
-#endif
-SH_DECL_HOOK0(IVEngineServer, GetMapEntitiesString, SH_NOATTRIB, 0, const char *);
-
-
-/**
- * CBaseEntity Hooks
- */
-SH_DECL_MANUALHOOK1_void(EndTouch, 0, 0, 0, CBaseEntity *);
-SH_DECL_MANUALHOOK1_void(FireBullets, 0, 0, 0, FireBulletsInfo_t const&);
-#ifdef GETMAXHEALTH_IS_VIRTUAL
-SH_DECL_MANUALHOOK0(GetMaxHealth, 0, 0, 0, int);
-#endif
-SH_DECL_MANUALHOOK1_void(GroundEntChanged, 0, 0, 0, void *);
-SH_DECL_MANUALHOOK1(OnTakeDamage, 0, 0, 0, int, CTakeDamageInfoHack &);
-SH_DECL_MANUALHOOK1(OnTakeDamage_Alive, 0, 0, 0, int, CTakeDamageInfoHack &);
-SH_DECL_MANUALHOOK0_void(PreThink, 0, 0, 0);
-SH_DECL_MANUALHOOK0_void(PostThink, 0, 0, 0);
-SH_DECL_MANUALHOOK0(Reload, 0, 0, 0, bool);
-SH_DECL_MANUALHOOK2_void(SetTransmit, 0, 0, 0, CCheckTransmitInfo *, bool);
-SH_DECL_MANUALHOOK2(ShouldCollide, 0, 0, 0, bool, int, int);
-SH_DECL_MANUALHOOK0_void(Spawn, 0, 0, 0);
-SH_DECL_MANUALHOOK1_void(StartTouch, 0, 0, 0, CBaseEntity *);
-SH_DECL_MANUALHOOK0_void(Think, 0, 0, 0);
-SH_DECL_MANUALHOOK1_void(Touch, 0, 0, 0, CBaseEntity *);
-#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 \
- || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_SDK2013
-SH_DECL_MANUALHOOK4_void(TraceAttack, 0, 0, 0, CTakeDamageInfoHack &, const Vector &, CGameTrace *, CDmgAccumulator *);
-#else
-SH_DECL_MANUALHOOK3_void(TraceAttack, 0, 0, 0, CTakeDamageInfoHack &, const Vector &, CGameTrace *);
-#endif
-SH_DECL_MANUALHOOK4_void(Use, 0, 0, 0, CBaseEntity *, CBaseEntity *, USE_TYPE, float);
-SH_DECL_MANUALHOOK1_void(VPhysicsUpdate, 0, 0, 0, IPhysicsObject *);
-SH_DECL_MANUALHOOK1(Weapon_CanSwitchTo, 0, 0, 0, bool, CBaseCombatWeapon *);
-SH_DECL_MANUALHOOK1(Weapon_CanUse, 0, 0, 0, bool, CBaseCombatWeapon *);
-SH_DECL_MANUALHOOK3_void(Weapon_Drop, 0, 0, 0, CBaseCombatWeapon *, const Vector *, const Vector *);
-SH_DECL_MANUALHOOK1_void(Weapon_Equip, 0, 0, 0, CBaseCombatWeapon *);
-SH_DECL_MANUALHOOK2(Weapon_Switch, 0, 0, 0, bool, CBaseCombatWeapon *, int);
-SH_DECL_MANUALHOOK1_void(Blocked, 0, 0, 0, CBaseEntity *);
-SH_DECL_MANUALHOOK0(CanBeAutobalanced, 0, 0, 0, bool);
-
-
-/**
- * Forwards
- */
-bool SDKHooks::SDK_OnLoad(char *error, size_t maxlength, bool late)
-{
- char buffer[256];
- g_pSM->BuildPath(Path_SM, buffer, sizeof(buffer)-1, "/extensions/sdkhooks.ext." PLATFORM_LIB_EXT);
- if (libsys->PathExists(buffer) && libsys->IsPathFile(buffer))
- {
- g_pSM->Format(error, maxlength-1, "SDKHooks 2.x cannot load while old version (sdkhooks.ext." PLATFORM_LIB_EXT ") is still in extensions dir");
- return false;
- }
-
- g_pSM->BuildPath(Path_SM, buffer, sizeof(buffer)-1, "/gamedata/sdkhooks.games.txt");
- if (libsys->PathExists(buffer) && libsys->IsPathFile(buffer))
- {
- g_pSM->Format(error, maxlength-1, "SDKHooks 2.x cannot load while old gamedata file (sdkhooks.games.txt) is still in gamedata dir");
- return false;
- }
-
- buffer[0] = '\0';
- if (!gameconfs->LoadGameConfigFile("sdkhooks.games", &g_pGameConf, buffer, sizeof(buffer)))
- {
- if (buffer[0])
- {
- g_pSM->Format(error, maxlength, "Could not read sdkhooks.games gamedata: %s", buffer);
- }
-
- return false;
- }
-
- memset(m_EntityCache, INVALID_EHANDLE_INDEX, sizeof(m_EntityCache));
-
- CUtlVector *entListeners = EntListeners();
- if (!entListeners)
- {
- g_pSM->Format(error, maxlength, "Failed to setup entity listeners");
- return false;
- }
-
- entListeners->AddToTail(this);
-
- sharesys->AddDependency(myself, "bintools.ext", true, true);
- sharesys->AddNatives(myself, g_Natives);
- sharesys->RegisterLibrary(myself, "sdkhooks");
- sharesys->AddInterface(myself, &g_Interface);
- sharesys->AddCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD");
- sharesys->AddCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport");
-
- playerhelpers->AddClientListener(&g_Interface);
-
- plsys->AddPluginsListener(&g_Interface);
-
- g_pOnEntityCreated = forwards->CreateForward("OnEntityCreated", ET_Ignore, 2, NULL, Param_Cell, Param_String);
- g_pOnEntityDestroyed = forwards->CreateForward("OnEntityDestroyed", ET_Ignore, 1, NULL, Param_Cell);
-#ifdef GAMEDESC_CAN_CHANGE
- g_pOnGetGameNameDescription = forwards->CreateForward("OnGetGameDescription", ET_Hook, 2, NULL, Param_String);
-#endif
- g_pOnLevelInit = forwards->CreateForward("OnLevelInit", ET_Hook, 2, NULL, Param_String, Param_String);
-
- SetupHooks();
-
-#if SOURCE_ENGINE >= SE_ORANGEBOX
- int index;
- CBaseHandle hndl;
- for (IHandleEntity *pEnt = (IHandleEntity *)servertools->FirstEntity(); pEnt; pEnt = (IHandleEntity *)servertools->NextEntity((CBaseEntity *)pEnt))
- {
- hndl = pEnt->GetRefEHandle();
- if (!hndl.IsValid())
- continue;
-
- index = hndl.GetEntryIndex();
- if (IsEntityIndexInRange(index))
- {
- m_EntityCache[index] = gamehelpers->IndexToReference(index);
- }
- else
- {
- g_pSM->LogError(myself, "SDKHooks::HandleEntityCreated - Got entity index out of range (%d)", index);
- }
- }
-#else
- for (int i = 0; i < NUM_ENT_ENTRIES; i++)
- {
- if (gamehelpers->ReferenceToEntity(i) != NULL)
- m_EntityCache[i] = gamehelpers->IndexToReference(i);
- }
-#endif
-
- return true;
-}
-
-inline void HookLevelInit()
-{
- assert(g_hookOnLevelInit == 0);
- g_hookOnLevelInit = SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(&g_Interface, &SDKHooks::Hook_LevelInit), false);
- assert(g_hookOnGetMapEntitiesString == 0);
- g_hookOnGetMapEntitiesString = SH_ADD_HOOK(IVEngineServer, GetMapEntitiesString, engine, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GetMapEntitiesString), false);
-}
-
-#ifdef GAMEDESC_CAN_CHANGE
-inline void HookGetGameDescription()
-{
- assert(g_hookOnGetGameDescription == 0);
- g_hookOnGetGameDescription = SH_ADD_HOOK(IServerGameDLL, GetGameDescription, gamedll, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GetGameDescription), false);
-}
-#endif
-
-void SDKHooks::SDK_OnAllLoaded()
-{
- SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
-
- if (!g_pBinTools)
- {
- g_pSM->LogError(myself, "Could not find interface: " SMINTERFACE_BINTOOLS_NAME);
- return;
- }
-
- if (g_pOnLevelInit->GetFunctionCount() > 0)
- HookLevelInit();
-#ifdef GAMEDESC_CAN_CHANGE
- if (g_pOnGetGameNameDescription->GetFunctionCount() > 0)
- HookGetGameDescription();
-#endif
-}
-
-#define KILL_HOOK_IF_ACTIVE(hook) \
- if (hook != 0) \
- { \
- SH_REMOVE_HOOK_ID(hook); \
- }
-
-void SDKHooks::SDK_OnUnload()
-{
- // Remove left over hooks
- Unhook(reinterpret_cast(NULL));
-
- KILL_HOOK_IF_ACTIVE(g_hookOnLevelInit);
- KILL_HOOK_IF_ACTIVE(g_hookOnGetMapEntitiesString);
-
-#ifdef GAMEDESC_CAN_CHANGE
- KILL_HOOK_IF_ACTIVE(g_hookOnGetGameDescription);
-#endif
-
- forwards->ReleaseForward(g_pOnEntityCreated);
- forwards->ReleaseForward(g_pOnEntityDestroyed);
-#ifdef GAMEDESC_CAN_CHANGE
- forwards->ReleaseForward(g_pOnGetGameNameDescription);
-#endif
- forwards->ReleaseForward(g_pOnLevelInit);
-
- plsys->RemovePluginsListener(&g_Interface);
-
- playerhelpers->RemoveClientListener(&g_Interface);
-
- sharesys->DropCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD");
- sharesys->DropCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport");
-
- CUtlVector *entListeners = EntListeners();
- entListeners->FindAndRemove(this);
-
- gameconfs->CloseGameConfigFile(g_pGameConf);
-}
-
-bool SDKHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
-{
- GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
-
-#if SOURCE_ENGINE >= SE_ORANGEBOX
- GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION);
- g_pCVar = icvar;
-#endif
- CONVAR_REGISTER(this);
-
- gpGlobals = ismm->GetCGlobals();
-
- return true;
-}
-
-const char *SDKHooks::GetExtensionVerString()
-{
- return SOURCEMOD_VERSION;
-}
-
-const char *SDKHooks::GetExtensionDateString()
-{
- return SOURCEMOD_BUILD_TIME;
-}
-
-void SDKHooks::OnPluginLoaded(IPlugin *plugin)
-{
- if (g_pOnLevelInit->GetFunctionCount() > 0 && g_hookOnLevelInit == 0)
- HookLevelInit();
-
-#ifdef GAMEDESC_CAN_CHANGE
- if (g_pOnGetGameNameDescription->GetFunctionCount() > 0 && g_hookOnGetGameDescription == 0)
- HookGetGameDescription();
-#endif
-}
-
-void SDKHooks::OnPluginUnloaded(IPlugin *plugin)
-{
- Unhook(plugin->GetBaseContext());
-
- if (g_pOnLevelInit->GetFunctionCount() == 0)
- {
- KILL_HOOK_IF_ACTIVE(g_hookOnLevelInit);
- KILL_HOOK_IF_ACTIVE(g_hookOnGetMapEntitiesString);
- }
-
-#ifdef GAMEDESC_CAN_CHANGE
- if (g_pOnGetGameNameDescription->GetFunctionCount() == 0)
- KILL_HOOK_IF_ACTIVE(g_hookOnGetGameDescription);
-#endif
-}
-
-void SDKHooks::OnClientPutInServer(int client)
-{
- CBaseEntity *pPlayer = gamehelpers->ReferenceToEntity(client);
-
- HandleEntityCreated(pPlayer, client, gamehelpers->EntityToReference(pPlayer));
-}
-
-void SDKHooks::OnClientDisconnecting(int client)
-{
- CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(client);
-
- HandleEntityDeleted(pEntity);
-}
-
-void SDKHooks::AddEntityListener(ISMEntityListener *listener)
-{
- m_EntListeners.push_back(listener);
-}
-
-void SDKHooks::RemoveEntityListener(ISMEntityListener *listener)
-{
- m_EntListeners.remove(listener);
-}
-
-bool SDKHooks::RegisterConCommandBase(ConCommandBase *pVar)
-{
- /* Always call META_REGCVAR instead of going through the engine. */
- return META_REGCVAR(pVar);
-}
-
-FeatureStatus SDKHooks::GetFeatureStatus(FeatureType type, const char *name)
-{
- return FeatureStatus_Available;
-}
-
-/**
- * Functions
- */
-
-static void PopulateCallbackList(const ke::Vector &source, ke::Vector &destination, int entity)
-{
- destination.ensure(8); /* Skip trivial allocations as AMTL uses length<<1. */
- for (size_t iter = 0; iter < source.length(); ++iter)
- {
- if (source[iter].entity != entity)
- {
- continue;
- }
-
- destination.append(source[iter].callback);
- }
-}
-
-cell_t SDKHooks::Call(int entity, SDKHookType type, int other)
-{
- return Call(gamehelpers->ReferenceToEntity(entity), type, gamehelpers->ReferenceToEntity(other));
-}
-
-cell_t SDKHooks::Call(CBaseEntity *pEnt, SDKHookType type, int other)
-{
- return Call(pEnt, type, gamehelpers->ReferenceToEntity(other));
-}
-
-cell_t SDKHooks::Call(CBaseEntity *pEnt, SDKHookType type, CBaseEntity *pOther)
-{
- cell_t ret = Pl_Continue;
-
- CVTableHook vhook(pEnt);
- ke::Vector &vtablehooklist = g_HookList[type];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEnt);
- int other = gamehelpers->EntityToBCompatRef(pOther);
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCell(other);
-
- cell_t res;
- callback->Execute(&res);
- if(res > ret)
- {
- ret = res;
- }
- }
-
- break;
- }
-
- return ret;
-}
-
-void SDKHooks::SetupHooks()
-{
- int offset;
-
- // gamedata pre post
- // (pre is not necessarily a prehook, just named without "Post" appeneded)
-
- CHECKOFFSET(EndTouch, true, true);
- CHECKOFFSET(FireBullets, false, true);
- CHECKOFFSET(GroundEntChanged, false, true);
- CHECKOFFSET(OnTakeDamage, true, true);
- CHECKOFFSET(OnTakeDamage_Alive,true, true);
- CHECKOFFSET(PreThink, true, true);
- CHECKOFFSET(PostThink, true, true);
- CHECKOFFSET(Reload, true, true);
- CHECKOFFSET(SetTransmit, true, false);
- CHECKOFFSET(ShouldCollide, true, false);
- CHECKOFFSET(Spawn, true, true);
- CHECKOFFSET(StartTouch, true, true);
- CHECKOFFSET(Think, true, true);
- CHECKOFFSET(Touch, true, true);
- CHECKOFFSET(TraceAttack, true, true);
- CHECKOFFSET(Use, true, true);
- CHECKOFFSET_W(CanSwitchTo, true, true);
- CHECKOFFSET_W(CanUse, true, true);
- CHECKOFFSET_W(Drop, true, true);
- CHECKOFFSET_W(Equip, true, true);
- CHECKOFFSET_W(Switch, true, true);
- CHECKOFFSET(VPhysicsUpdate, true, true);
- CHECKOFFSET(Blocked, true, true);
- CHECKOFFSET(CanBeAutobalanced, true, false);
-
- // this one is in a class all its own -_-
- offset = 0;
- g_pGameConf->GetOffset("GroundEntChanged", &offset);
- if (offset > 0)
- {
- SH_MANUALHOOK_RECONFIGURE(GroundEntChanged, offset, 0, 0);
- g_HookTypes[SDKHook_GroundEntChangedPost].supported = true;
- }
-
-#ifdef GETMAXHEALTH_IS_VIRTUAL
- CHECKOFFSET(GetMaxHealth, true, false);
-#endif
-}
-
-HookReturn SDKHooks::Hook(int entity, SDKHookType type, IPluginFunction *callback)
-{
- if(!g_HookTypes[type].supported)
- return HookRet_NotSupported;
-
- CBaseEntity *pEnt = gamehelpers->ReferenceToEntity(entity);
- if(!pEnt)
- return HookRet_InvalidEntity;
- if(type < 0 || type >= SDKHook_MAXHOOKS)
- return HookRet_InvalidHookType;
-
- if (!!strcmp(g_HookTypes[type].dtReq, ""))
- {
- IServerUnknown *pUnk = (IServerUnknown *)pEnt;
-
- IServerNetworkable *pNet = pUnk->GetNetworkable();
- if (pNet && !UTIL_ContainsDataTable(pNet->GetServerClass()->m_pTable, g_HookTypes[type].dtReq))
- return HookRet_BadEntForHookType;
- }
-
- size_t entry;
- CVTableHook vhook(pEnt);
- ke::Vector &vtablehooklist = g_HookList[type];
- for (entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook == vtablehooklist[entry]->vtablehook)
- {
- break;
- }
- }
-
- if (entry == vtablehooklist.length())
- {
- int hookid = 0;
- switch(type)
- {
- case SDKHook_EndTouch:
- hookid = SH_ADD_MANUALVPHOOK(EndTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_EndTouch), false);
- break;
- case SDKHook_EndTouchPost:
- hookid = SH_ADD_MANUALVPHOOK(EndTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_EndTouchPost), true);
- break;
- case SDKHook_FireBulletsPost:
- hookid = SH_ADD_MANUALVPHOOK(FireBullets, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_FireBulletsPost), true);
- break;
-#ifdef GETMAXHEALTH_IS_VIRTUAL
- case SDKHook_GetMaxHealth:
- hookid = SH_ADD_MANUALVPHOOK(GetMaxHealth, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GetMaxHealth), false);
- break;
-#endif
- case SDKHook_GroundEntChangedPost:
- hookid = SH_ADD_MANUALVPHOOK(GroundEntChanged, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GroundEntChangedPost), true);
- break;
- case SDKHook_OnTakeDamage:
- hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamage), false);
- break;
- case SDKHook_OnTakeDamagePost:
- hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamagePost), true);
- break;
- case SDKHook_OnTakeDamage_Alive:
- hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage_Alive, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamage_Alive), false);
- break;
- case SDKHook_OnTakeDamage_AlivePost:
- hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage_Alive, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamage_AlivePost), true);
- break;
- case SDKHook_PreThink:
- hookid = SH_ADD_MANUALVPHOOK(PreThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PreThink), false);
- break;
- case SDKHook_PreThinkPost:
- hookid = SH_ADD_MANUALVPHOOK(PreThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PreThinkPost), true);
- break;
- case SDKHook_PostThink:
- hookid = SH_ADD_MANUALVPHOOK(PostThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PostThink), false);
- break;
- case SDKHook_PostThinkPost:
- hookid = SH_ADD_MANUALVPHOOK(PostThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PostThinkPost), true);
- break;
- case SDKHook_Reload:
- hookid = SH_ADD_MANUALVPHOOK(Reload, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Reload), false);
- break;
- case SDKHook_ReloadPost:
- hookid = SH_ADD_MANUALVPHOOK(Reload, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_ReloadPost), true);
- break;
- case SDKHook_SetTransmit:
- hookid = SH_ADD_MANUALVPHOOK(SetTransmit, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_SetTransmit), false);
- break;
- case SDKHook_Spawn:
- hookid = SH_ADD_MANUALVPHOOK(Spawn, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Spawn), false);
- break;
- case SDKHook_SpawnPost:
- hookid = SH_ADD_MANUALVPHOOK(Spawn, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_SpawnPost), true);
- break;
- case SDKHook_StartTouch:
- hookid = SH_ADD_MANUALVPHOOK(StartTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_StartTouch), false);
- break;
- case SDKHook_StartTouchPost:
- hookid = SH_ADD_MANUALVPHOOK(StartTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_StartTouchPost), true);
- break;
- case SDKHook_Think:
- hookid = SH_ADD_MANUALVPHOOK(Think, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Think), false);
- break;
- case SDKHook_ThinkPost:
- hookid = SH_ADD_MANUALVPHOOK(Think, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_ThinkPost), true);
- break;
- case SDKHook_Touch:
- hookid = SH_ADD_MANUALVPHOOK(Touch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Touch), false);
- break;
- case SDKHook_TouchPost:
- hookid = SH_ADD_MANUALVPHOOK(Touch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_TouchPost), true);
- break;
- case SDKHook_TraceAttack:
- hookid = SH_ADD_MANUALVPHOOK(TraceAttack, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_TraceAttack), false);
- break;
- case SDKHook_TraceAttackPost:
- hookid = SH_ADD_MANUALVPHOOK(TraceAttack, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_TraceAttackPost), true);
- break;
- case SDKHook_Use:
- hookid = SH_ADD_MANUALVPHOOK(Use, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Use), false);
- break;
- case SDKHook_UsePost:
- hookid = SH_ADD_MANUALVPHOOK(Use, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_UsePost), true);
- break;
- case SDKHook_VPhysicsUpdate:
- hookid = SH_ADD_MANUALVPHOOK(VPhysicsUpdate, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_VPhysicsUpdate), false);
- break;
- case SDKHook_VPhysicsUpdatePost:
- hookid = SH_ADD_MANUALVPHOOK(VPhysicsUpdate, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_VPhysicsUpdatePost), true);
- break;
- case SDKHook_WeaponCanSwitchTo:
- hookid = SH_ADD_MANUALVPHOOK(Weapon_CanSwitchTo, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanSwitchTo), false);
- break;
- case SDKHook_WeaponCanSwitchToPost:
- hookid = SH_ADD_MANUALVPHOOK(Weapon_CanSwitchTo, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanSwitchToPost), true);
- break;
- case SDKHook_WeaponCanUse:
- hookid = SH_ADD_MANUALVPHOOK(Weapon_CanUse, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanUse), false);
- break;
- case SDKHook_WeaponCanUsePost:
- hookid = SH_ADD_MANUALVPHOOK(Weapon_CanUse, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanUsePost), true);
- break;
- case SDKHook_WeaponDrop:
- hookid = SH_ADD_MANUALVPHOOK(Weapon_Drop, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponDrop), false);
- break;
- case SDKHook_WeaponDropPost:
- hookid = SH_ADD_MANUALVPHOOK(Weapon_Drop, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponDropPost), true);
- break;
- case SDKHook_WeaponEquip:
- hookid = SH_ADD_MANUALVPHOOK(Weapon_Equip, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponEquip), false);
- break;
- case SDKHook_WeaponEquipPost:
- hookid = SH_ADD_MANUALVPHOOK(Weapon_Equip, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponEquipPost), true);
- break;
- case SDKHook_WeaponSwitch:
- hookid = SH_ADD_MANUALVPHOOK(Weapon_Switch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponSwitch), false);
- break;
- case SDKHook_WeaponSwitchPost:
- hookid = SH_ADD_MANUALVPHOOK(Weapon_Switch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponSwitchPost), true);
- break;
- case SDKHook_ShouldCollide:
- hookid = SH_ADD_MANUALVPHOOK(ShouldCollide, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_ShouldCollide), false);
- break;
- case SDKHook_Blocked:
- hookid = SH_ADD_MANUALVPHOOK(Blocked, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Blocked), false);
- break;
- case SDKHook_BlockedPost:
- hookid = SH_ADD_MANUALVPHOOK(Blocked, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_BlockedPost), true);
- break;
- case SDKHook_CanBeAutobalanced:
- hookid = SH_ADD_MANUALVPHOOK(CanBeAutobalanced, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_CanBeAutobalanced), false);
- break;
- }
-
- vhook.SetHookID(hookid);
-
- CVTableList *vtablelist = new CVTableList;
- vtablelist->vtablehook = new CVTableHook(vhook);
- vtablehooklist.append(vtablelist);
- }
-
- // Add hook to hook list
- HookList hook;
- hook.entity = gamehelpers->EntityToBCompatRef(pEnt);
- hook.callback = callback;
- vtablehooklist[entry]->hooks.append(hook);
-
- return HookRet_Successful;
-}
-
-void SDKHooks::Unhook(CBaseEntity *pEntity)
-{
- if (pEntity == NULL)
- {
- return;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
- for (size_t type = 0; type < SDKHook_MAXHOOKS; ++type)
- {
- ke::Vector &vtablehooklist = g_HookList[type];
- for (size_t listentry = 0; listentry < vtablehooklist.length(); ++listentry)
- {
- ke::Vector &pawnhooks = vtablehooklist[listentry]->hooks;
- for (size_t entry = 0; entry < pawnhooks.length(); ++entry)
- {
- if (entity != pawnhooks[entry].entity)
- {
- continue;
- }
-
- pawnhooks.remove(entry--);
- }
-
- if (pawnhooks.length() == 0)
- {
- delete vtablehooklist[listentry];
- vtablehooklist.remove(listentry--);
- }
- }
- }
-}
-
-void SDKHooks::Unhook(IPluginContext *pContext)
-{
- for (size_t type = 0; type < SDKHook_MAXHOOKS; ++type)
- {
- ke::Vector &vtablehooklist = g_HookList[type];
- for (size_t listentry = 0; listentry < vtablehooklist.length(); ++listentry)
- {
- ke::Vector &pawnhooks = vtablehooklist[listentry]->hooks;
- for (size_t entry = 0; entry < pawnhooks.length(); ++entry)
- {
- if (pContext != NULL && pContext != pawnhooks[entry].callback->GetParentRuntime()->GetDefaultContext())
- {
- continue;
- }
-
- pawnhooks.remove(entry--);
- }
-
- if (pawnhooks.length() == 0)
- {
- delete vtablehooklist[listentry];
- vtablehooklist.remove(listentry--);
- }
- }
- }
-}
-
-void SDKHooks::Unhook(int entity, SDKHookType type, IPluginFunction *pCallback)
-{
- CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(entity);
- if (pEntity == NULL)
- {
- return;
- }
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[type];
- for (size_t listentry = 0; listentry < vtablehooklist.length(); ++listentry)
- {
- if (vhook != vtablehooklist[listentry]->vtablehook)
- {
- continue;
- }
-
- entity = gamehelpers->EntityToBCompatRef(pEntity);
-
- ke::Vector &pawnhooks = vtablehooklist[listentry]->hooks;
- for (size_t entry = 0; entry < pawnhooks.length(); ++entry)
- {
- HookList &hookentry = pawnhooks[entry];
- if (entity != hookentry.entity || pCallback != hookentry.callback)
- {
- continue;
- }
-
- pawnhooks.remove(entry--);
- }
-
- if (pawnhooks.length() == 0)
- {
- delete vtablehooklist[listentry];
- vtablehooklist.remove(listentry);
- }
-
- break;
- }
-}
-
-/**
- * IEntityFactoryDictionary, IServerGameDLL & IVEngineServer Hook Handlers
- */
-void SDKHooks::OnEntityCreated(CBaseEntity *pEntity)
-{
- // Call OnEntityCreated forward
- int ref = gamehelpers->EntityToReference(pEntity);
- int index = gamehelpers->ReferenceToIndex(ref);
-
- // This can be -1 for player ents before any players have connected
- if ((unsigned)index == INVALID_EHANDLE_INDEX || (index > 0 && index <= playerhelpers->GetMaxClients()))
- {
- return;
- }
-
- if (!IsEntityIndexInRange(index))
- {
- g_pSM->LogError(myself, "SDKHooks::OnEntityCreated - Got entity index out of range (%d)", index);
- return;
- }
-
- // The entity could already exist. The creation notifier fires twice for some paths
- if (m_EntityCache[index] != ref)
- {
- HandleEntityCreated(pEntity, index, ref);
- }
-}
-
-#ifdef GAMEDESC_CAN_CHANGE
-const char *SDKHooks::Hook_GetGameDescription()
-{
- static char szGameDesc[64];
- cell_t result = Pl_Continue;
-
- g_pSM->Format(szGameDesc, sizeof(szGameDesc), "%s",
- SH_CALL(gamedll, &IServerGameDLL::GetGameDescription)());
-
- // Call OnGetGameDescription forward
- g_pOnGetGameNameDescription->PushStringEx(szGameDesc, sizeof(szGameDesc), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
- g_pOnGetGameNameDescription->Execute(&result);
-
- if(result == Pl_Changed)
- RETURN_META_VALUE(MRES_SUPERCEDE, szGameDesc);
-
- RETURN_META_VALUE(MRES_IGNORED, NULL);
-}
-#endif
-
-const char *SDKHooks::Hook_GetMapEntitiesString()
-{
- if(g_szMapEntities[0])
- RETURN_META_VALUE(MRES_SUPERCEDE, g_szMapEntities);
-
- RETURN_META_VALUE(MRES_IGNORED, NULL);
-}
-
-bool SDKHooks::Hook_LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
-{
- strcpy(g_szMapEntities, pMapEntities);
- cell_t result = Pl_Continue;
-
- // Call OnLevelInit forward
- g_pOnLevelInit->PushString(pMapName);
- g_pOnLevelInit->PushStringEx(g_szMapEntities, sizeof(g_szMapEntities), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
- g_pOnLevelInit->Execute(&result);
-
- if(result == Pl_Changed)
- RETURN_META_VALUE_NEWPARAMS(MRES_HANDLED, true, &IServerGameDLL::LevelInit, (pMapName, g_szMapEntities, pOldLevel, pLandmarkName, loadGame, background));
-
- RETURN_META_VALUE(MRES_IGNORED, true);
-}
-
-
-/**
- * CBaseEntity Hook Handlers
- */
-bool SDKHooks::Hook_CanBeAutobalanced()
-{
- CBaseEntity *pPlayer = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pPlayer);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_CanBeAutobalanced];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pPlayer);
-
- bool origRet = SH_MCALL(pPlayer, CanBeAutobalanced)();
- bool newRet = origRet;
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- cell_t res = origRet;
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCell(origRet);
- callback->Execute(&res);
-
- // Only update our new ret if different from original
- // (so if multiple plugins returning different answers,
- // the one(s) that changed it win)
- if ((bool)res != origRet)
- newRet = !origRet;
- }
-
- if (newRet != origRet)
- RETURN_META_VALUE(MRES_SUPERCEDE, newRet);
-
- break;
- }
-
- RETURN_META_VALUE(MRES_IGNORED, false);
-}
-
-void SDKHooks::Hook_EndTouch(CBaseEntity *pOther)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_EndTouch, pOther);
- if(result >= Pl_Handled)
- RETURN_META(MRES_SUPERCEDE);
-
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_EndTouchPost(CBaseEntity *pOther)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_EndTouchPost, pOther);
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_FireBulletsPost(const FireBulletsInfo_t &info)
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
-
- IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(entity);
- if(!pPlayer)
- RETURN_META(MRES_IGNORED);
-
- IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
- if(!pInfo)
- RETURN_META(MRES_IGNORED);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_FireBulletsPost];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- const char *weapon = pInfo->GetWeaponName();
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCell(info.m_iShots);
- callback->PushString(weapon?weapon:"");
- callback->Execute(NULL);
- }
-
- break;
- }
-
- RETURN_META(MRES_IGNORED);
-}
-
-#ifdef GETMAXHEALTH_IS_VIRTUAL
-int SDKHooks::Hook_GetMaxHealth()
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
- int original_max = SH_MCALL(pEntity, GetMaxHealth)();
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_GetMaxHealth];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
-
- int new_max = original_max;
-
- cell_t res = Pl_Continue;
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCellByRef(&new_max);
- callback->Execute(&res);
- }
-
- if (res >= Pl_Changed)
- RETURN_META_VALUE(MRES_SUPERCEDE, new_max);
-
- break;
- }
-
- RETURN_META_VALUE(MRES_IGNORED, original_max);
-}
-#endif
-
-void SDKHooks::Hook_GroundEntChangedPost(void *pVar)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_GroundEntChangedPost);
-}
-
-int SDKHooks::HandleOnTakeDamageHook(CTakeDamageInfoHack &info, SDKHookType hookType)
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[hookType];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
- int attacker = info.GetAttacker();
- int inflictor = info.GetInflictor();
- float damage = info.GetDamage();
- int damagetype = info.GetDamageType();
- int weapon = info.GetWeapon();
-
- Vector force = info.GetDamageForce();
- cell_t damageForce[3] = { sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z) };
-
- Vector pos = info.GetDamagePosition();
- cell_t damagePosition[3] = { sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z) };
-
- cell_t res, ret = Pl_Continue;
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCellByRef(&attacker);
- callback->PushCellByRef(&inflictor);
- callback->PushFloatByRef(&damage);
- callback->PushCellByRef(&damagetype);
- callback->PushCellByRef(&weapon);
- callback->PushArray(damageForce, 3, SM_PARAM_COPYBACK);
- callback->PushArray(damagePosition, 3, SM_PARAM_COPYBACK);
- callback->PushCell(info.GetDamageCustom());
- callback->Execute(&res);
-
- if (res >= ret)
- {
- ret = res;
- if (ret == Pl_Changed)
- {
- CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker);
- if (!pEntAttacker)
- {
- callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for attacker is invalid", attacker);
- RETURN_META_VALUE(MRES_IGNORED, 0);
- }
- CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor);
- if (!pEntInflictor)
- {
- callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for inflictor is invalid", inflictor);
- RETURN_META_VALUE(MRES_IGNORED, 0);
- }
-
- info.SetAttacker(pEntAttacker);
- info.SetInflictor(pEntInflictor);
- info.SetDamage(damage);
- info.SetDamageType(damagetype);
- info.SetWeapon(gamehelpers->ReferenceToEntity(weapon));
- info.SetDamageForce(
- sp_ctof(damageForce[0]),
- sp_ctof(damageForce[1]),
- sp_ctof(damageForce[2]));
- info.SetDamagePosition(
- sp_ctof(damagePosition[0]),
- sp_ctof(damagePosition[1]),
- sp_ctof(damagePosition[2]));
- }
- }
- }
-
- if (ret >= Pl_Handled)
- RETURN_META_VALUE(MRES_SUPERCEDE, 1);
-
- if (ret == Pl_Changed)
- RETURN_META_VALUE(MRES_HANDLED, 1);
-
- break;
- }
-
- RETURN_META_VALUE(MRES_IGNORED, 0);
-}
-
-int SDKHooks::HandleOnTakeDamageHookPost(CTakeDamageInfoHack &info, SDKHookType hookType)
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[hookType];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCell(info.GetAttacker());
- callback->PushCell(info.GetInflictor());
- callback->PushFloat(info.GetDamage());
- callback->PushCell(info.GetDamageType());
- callback->PushCell(info.GetWeapon());
-
- Vector force = info.GetDamageForce();
- cell_t damageForce[3] = { sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z) };
- callback->PushArray(damageForce, 3);
-
- Vector pos = info.GetDamagePosition();
- cell_t damagePosition[3] = { sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z) };
- callback->PushArray(damagePosition, 3);
-
- callback->PushCell(info.GetDamageCustom());
-
- callback->Execute(NULL);
- }
-
- break;
- }
-
- RETURN_META_VALUE(MRES_IGNORED, 0);
-}
-
-int SDKHooks::Hook_OnTakeDamage(CTakeDamageInfoHack &info)
-{
- return HandleOnTakeDamageHook(info, SDKHook_OnTakeDamage);
-}
-
-int SDKHooks::Hook_OnTakeDamagePost(CTakeDamageInfoHack &info)
-{
- return HandleOnTakeDamageHookPost(info, SDKHook_OnTakeDamagePost);
-}
-
-int SDKHooks::Hook_OnTakeDamage_Alive(CTakeDamageInfoHack &info)
-{
- return HandleOnTakeDamageHook(info, SDKHook_OnTakeDamage_Alive);
-}
-
-int SDKHooks::Hook_OnTakeDamage_AlivePost(CTakeDamageInfoHack &info)
-{
- return HandleOnTakeDamageHookPost(info, SDKHook_OnTakeDamage_AlivePost);
-}
-
-void SDKHooks::Hook_PreThink()
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_PreThink);
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_PreThinkPost()
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_PreThinkPost);
-}
-
-void SDKHooks::Hook_PostThink()
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_PostThink);
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_PostThinkPost()
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_PostThinkPost);
-}
-
-bool SDKHooks::Hook_Reload()
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_Reload];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
- cell_t res = Pl_Continue;
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->Execute(&res);
- }
-
- if (res >= Pl_Handled)
- RETURN_META_VALUE(MRES_SUPERCEDE, false);
-
- break;
- }
-
- RETURN_META_VALUE(MRES_IGNORED, true);
-}
-
-bool SDKHooks::Hook_ReloadPost()
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_ReloadPost];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
- cell_t origreturn = META_RESULT_ORIG_RET(bool) ? 1 : 0;
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCell(origreturn);
- callback->Execute(NULL);
- }
-
- break;
- }
-
- return true;
-}
-
-void SDKHooks::Hook_SetTransmit(CCheckTransmitInfo *pInfo, bool bAlways)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_SetTransmit, gamehelpers->IndexOfEdict(pInfo->m_pClientEnt));
-
- if(result >= Pl_Handled)
- RETURN_META(MRES_SUPERCEDE);
-
- RETURN_META(MRES_IGNORED);
-}
-
-bool SDKHooks::Hook_ShouldCollide(int collisionGroup, int contentsMask)
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_ShouldCollide];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
- cell_t origRet = ((META_RESULT_STATUS >= MRES_OVERRIDE)?(META_RESULT_OVERRIDE_RET(bool)):(META_RESULT_ORIG_RET(bool))) ? 1 : 0;
- cell_t res = 0;
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCell(collisionGroup);
- callback->PushCell(contentsMask);
- callback->PushCell(origRet);
- callback->Execute(&res);
- }
-
- bool ret = false;
- if (res != 0)
- {
- ret = true;
- }
-
- RETURN_META_VALUE(MRES_SUPERCEDE, ret);
- }
-
- RETURN_META_VALUE(MRES_IGNORED, true);
-}
-
-void SDKHooks::Hook_Spawn()
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_Spawn];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
- cell_t res = Pl_Continue;
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->Execute(&res);
- }
-
- if (res >= Pl_Handled)
- RETURN_META(MRES_SUPERCEDE);
-
- break;
- }
-
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_SpawnPost()
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_SpawnPost);
-}
-
-void SDKHooks::Hook_StartTouch(CBaseEntity *pOther)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_StartTouch, pOther);
- if(result >= Pl_Handled)
- RETURN_META(MRES_SUPERCEDE);
-
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_StartTouchPost(CBaseEntity *pOther)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_StartTouchPost, pOther);
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_Think()
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_Think);
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_ThinkPost()
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_ThinkPost);
-}
-
-void SDKHooks::Hook_Touch(CBaseEntity *pOther)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_Touch, pOther);
-
- if(result >= Pl_Handled)
- RETURN_META(MRES_SUPERCEDE);
-
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_TouchPost(CBaseEntity *pOther)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_TouchPost, pOther);
- RETURN_META(MRES_IGNORED);
-}
-
-#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 \
- || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_SDK2013
-void SDKHooks::Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator)
-#else
-void SDKHooks::Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr)
-#endif
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_TraceAttack];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
- int attacker = info.GetAttacker();
- int inflictor = info.GetInflictor();
- float damage = info.GetDamage();
- int damagetype = info.GetDamageType();
- int ammotype = info.GetAmmoType();
- cell_t res, ret = Pl_Continue;
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCellByRef(&attacker);
- callback->PushCellByRef(&inflictor);
- callback->PushFloatByRef(&damage);
- callback->PushCellByRef(&damagetype);
- callback->PushCellByRef(&ammotype);
- callback->PushCell(ptr->hitbox);
- callback->PushCell(ptr->hitgroup);
- callback->Execute(&res);
-
- if(res > ret)
- {
- ret = res;
-
- if(ret == Pl_Changed)
- {
- CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker);
- if(!pEntAttacker)
- {
- callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for attacker is invalid", attacker);
- RETURN_META(MRES_IGNORED);
- }
- CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor);
- if(!pEntInflictor)
- {
- callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for inflictor is invalid", inflictor);
- RETURN_META(MRES_IGNORED);
- }
-
- info.SetAttacker(pEntAttacker);
- info.SetInflictor(pEntInflictor);
- info.SetDamage(damage);
- info.SetDamageType(damagetype);
- info.SetAmmoType(ammotype);
- }
- }
- }
-
- if(ret >= Pl_Handled)
- RETURN_META(MRES_SUPERCEDE);
-
- if(ret == Pl_Changed)
- RETURN_META(MRES_HANDLED);
-
- break;
- }
-
- RETURN_META(MRES_IGNORED);
-}
-
-#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 \
- || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_SDK2013
-void SDKHooks::Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator)
-#else
-void SDKHooks::Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr)
-#endif
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_TraceAttackPost];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCell(info.GetAttacker());
- callback->PushCell(info.GetInflictor());
- callback->PushFloat(info.GetDamage());
- callback->PushCell(info.GetDamageType());
- callback->PushCell(info.GetAmmoType());
- callback->PushCell(ptr->hitbox);
- callback->PushCell(ptr->hitgroup);
- callback->Execute(NULL);
- }
-
- break;
- }
-
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_Use];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
- int activator = gamehelpers->EntityToBCompatRef(pActivator);
- int caller = gamehelpers->EntityToBCompatRef(pCaller);
- cell_t ret = Pl_Continue;
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCell(activator);
- callback->PushCell(caller);
- callback->PushCell(useType);
- callback->PushFloat(value);
- callback->Execute(&ret);
- }
-
- if (ret >= Pl_Handled)
- RETURN_META(MRES_SUPERCEDE);
-
- break;
- }
-
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_UsePost(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
-{
- CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
-
- CVTableHook vhook(pEntity);
- ke::Vector &vtablehooklist = g_HookList[SDKHook_UsePost];
- for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
- {
- if (vhook != vtablehooklist[entry]->vtablehook)
- {
- continue;
- }
-
- int entity = gamehelpers->EntityToBCompatRef(pEntity);
- int activator = gamehelpers->EntityToBCompatRef(pActivator);
- int caller = gamehelpers->EntityToBCompatRef(pCaller);
-
- ke::Vector callbackList;
- PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
- for (entry = 0; entry < callbackList.length(); ++entry)
- {
- IPluginFunction *callback = callbackList[entry];
- callback->PushCell(entity);
- callback->PushCell(activator);
- callback->PushCell(caller);
- callback->PushCell(useType);
- callback->PushFloat(value);
- callback->Execute(NULL);
- }
-
- break;
- }
-
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::OnEntityDeleted(CBaseEntity *pEntity)
-{
- int index = gamehelpers->ReferenceToIndex(gamehelpers->EntityToReference(pEntity));
-
- // This can be -1 for player ents before any players have connected
- if ((unsigned)index == INVALID_EHANDLE_INDEX || (index > 0 && index <= playerhelpers->GetMaxClients()))
- {
- return;
- }
-
- HandleEntityDeleted(pEntity);
-}
-
-void SDKHooks::Hook_VPhysicsUpdate(IPhysicsObject *pPhysics)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_VPhysicsUpdate);
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_VPhysicsUpdatePost(IPhysicsObject *pPhysics)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_VPhysicsUpdatePost);
-}
-
-void SDKHooks::Hook_Blocked(CBaseEntity *pOther)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_Blocked, pOther);
-
- if(result >= Pl_Handled)
- RETURN_META(MRES_SUPERCEDE);
-
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_BlockedPost(CBaseEntity *pOther)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_BlockedPost, pOther);
- RETURN_META(MRES_IGNORED);
-}
-
-bool SDKHooks::Hook_WeaponCanSwitchTo(CBaseCombatWeapon *pWeapon)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanSwitchTo, pWeapon);
-
- if(result >= Pl_Handled)
- RETURN_META_VALUE(MRES_SUPERCEDE, false);
-
- RETURN_META_VALUE(MRES_IGNORED, true);
-}
-
-bool SDKHooks::Hook_WeaponCanSwitchToPost(CBaseCombatWeapon *pWeapon)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanSwitchToPost, pWeapon);
- RETURN_META_VALUE(MRES_IGNORED, true);
-}
-
-bool SDKHooks::Hook_WeaponCanUse(CBaseCombatWeapon *pWeapon)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanUse, pWeapon);
-
- if(result >= Pl_Handled)
- RETURN_META_VALUE(MRES_SUPERCEDE, false);
-
- RETURN_META_VALUE(MRES_IGNORED, true);
-}
-
-bool SDKHooks::Hook_WeaponCanUsePost(CBaseCombatWeapon *pWeapon)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanUsePost, pWeapon);
- RETURN_META_VALUE(MRES_IGNORED, true);
-}
-
-void SDKHooks::Hook_WeaponDrop(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponDrop, pWeapon);
-
- if(result >= Pl_Handled)
- RETURN_META(MRES_SUPERCEDE);
-
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_WeaponDropPost(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponDropPost, pWeapon);
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_WeaponEquip(CBaseCombatWeapon *pWeapon)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponEquip, pWeapon);
-
- if(result >= Pl_Handled)
- RETURN_META(MRES_SUPERCEDE);
-
- RETURN_META(MRES_IGNORED);
-}
-
-void SDKHooks::Hook_WeaponEquipPost(CBaseCombatWeapon *pWeapon)
-{
- Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponEquipPost, pWeapon);
- RETURN_META(MRES_IGNORED);
-}
-
-bool SDKHooks::Hook_WeaponSwitch(CBaseCombatWeapon *pWeapon, int viewmodelindex)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponSwitch, pWeapon);
-
- if(result >= Pl_Handled)
- RETURN_META_VALUE(MRES_SUPERCEDE, false);
-
- RETURN_META_VALUE(MRES_IGNORED, true);
-}
-
-bool SDKHooks::Hook_WeaponSwitchPost(CBaseCombatWeapon *pWeapon, int viewmodelindex)
-{
- cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponSwitchPost, pWeapon);
- RETURN_META_VALUE(MRES_IGNORED, true);
-}
-
-void SDKHooks::HandleEntityCreated(CBaseEntity *pEntity, int index, cell_t ref)
-{
- const char *pName = gamehelpers->GetEntityClassname(pEntity);
- cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity);
-
- // Send OnEntityCreated to SM listeners
- SourceHook::List::iterator iter;
- ISMEntityListener *pListener = NULL;
- for (iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++)
- {
- pListener = (*iter);
- pListener->OnEntityCreated(pEntity, pName ? pName : "");
- }
-
- // Call OnEntityCreated forward
- g_pOnEntityCreated->PushCell(bcompatRef);
- g_pOnEntityCreated->PushString(pName ? pName : "");
- g_pOnEntityCreated->Execute(NULL);
-
- m_EntityCache[index] = ref;
-}
-
-void SDKHooks::HandleEntityDeleted(CBaseEntity *pEntity)
-{
- cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity);
-
- // Send OnEntityDestroyed to SM listeners
- SourceHook::List::iterator iter;
- ISMEntityListener *pListener = NULL;
- for (iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++)
- {
- pListener = (*iter);
- pListener->OnEntityDestroyed(pEntity);
- }
-
- // Call OnEntityDestroyed forward
- g_pOnEntityDestroyed->PushCell(bcompatRef);
- g_pOnEntityDestroyed->Execute(NULL);
-
- Unhook(pEntity);
-}
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * Source SDK Hooks Extension
+ * Copyright (C) 2010-2012 Nicholas Hastings
+ * Copyright (C) 2009-2010 Erik Minekus
+ * =============================================================================
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 3.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id$
+ */
+
+#include
+#include "extension.h"
+#include "compat_wrappers.h"
+#include "macros.h"
+#include "natives.h"
+#include
+#include
+
+
+//#define SDKHOOKSDEBUG
+
+/**
+ * Globals
+ */
+
+// Order MUST match SDKHookType enum
+HookTypeData g_HookTypes[SDKHook_MAXHOOKS] =
+{
+// Hook name DT required Supported (always false til later)
+ {"EndTouch", "", false},
+ {"FireBulletsPost", "", false},
+ {"OnTakeDamage", "", false},
+ {"OnTakeDamagePost", "", false},
+ {"PreThink", "DT_BasePlayer", false},
+ {"PostThink", "DT_BasePlayer", false},
+ {"SetTransmit", "", false},
+ {"Spawn", "", false},
+ {"StartTouch", "", false},
+ {"Think", "", false},
+ {"Touch", "", false},
+ {"TraceAttack", "", false},
+ {"TraceAttackPost", "", false},
+ {"WeaponCanSwitchTo", "DT_BaseCombatCharacter", false},
+ {"WeaponCanUse", "DT_BaseCombatCharacter", false},
+ {"WeaponDrop", "DT_BaseCombatCharacter", false},
+ {"WeaponEquip", "DT_BaseCombatCharacter", false},
+ {"WeaponSwitch", "DT_BaseCombatCharacter", false},
+ {"ShouldCollide", "", false},
+ {"PreThinkPost", "DT_BasePlayer", false},
+ {"PostThinkPost", "DT_BasePlayer", false},
+ {"ThinkPost", "", false},
+ {"EndTouchPost", "", false},
+ {"GroundEntChangedPost", "", false},
+ {"SpawnPost", "", false},
+ {"StartTouchPost", "", false},
+ {"TouchPost", "", false},
+ {"VPhysicsUpdate", "", false},
+ {"VPhysicsUpdatePost", "", false},
+ {"WeaponCanSwitchToPost", "DT_BaseCombatCharacter", false},
+ {"WeaponCanUsePost", "DT_BaseCombatCharacter", false},
+ {"WeaponDropPost", "DT_BaseCombatCharacter", false},
+ {"WeaponEquipPost", "DT_BaseCombatCharacter", false},
+ {"WeaponSwitchPost", "DT_BaseCombatCharacter", false},
+ {"Use", "", false},
+ {"UsePost", "", false},
+ {"Reload", "DT_BaseCombatWeapon", false},
+ {"ReloadPost", "DT_BaseCombatWeapon", false},
+ {"GetMaxHealth", "", false},
+ {"Blocked", "", false},
+ {"BlockedPost", "", false},
+ {"OnTakeDamageAlive", "DT_BaseCombatCharacter", false},
+ {"OnTakeDamageAlivePost", "DT_BaseCombatCharacter", false},
+
+ // There is no DT for CBaseMultiplayerPlayer. Going up a level
+ {"CanBeAutobalanced", "DT_BasePlayer", false},
+};
+
+SDKHooks g_Interface;
+SMEXT_LINK(&g_Interface);
+
+CGlobalVars *gpGlobals;
+ke::Vector g_HookList[SDKHook_MAXHOOKS];
+
+IBinTools *g_pBinTools = NULL;
+ICvar *icvar = NULL;
+
+#if SOURCE_ENGINE >= SE_ORANGEBOX
+IServerTools *servertools = NULL;
+#endif
+
+// global hooks and forwards
+IForward *g_pOnEntityCreated = NULL;
+IForward *g_pOnEntityDestroyed = NULL;
+
+#ifdef GAMEDESC_CAN_CHANGE
+int g_hookOnGetGameDescription = 0;
+IForward *g_pOnGetGameNameDescription = NULL;
+#endif
+
+int g_hookOnGetMapEntitiesString = 0;
+int g_hookOnLevelInit = 0;
+IForward *g_pOnLevelInit = NULL;
+
+IGameConfig *g_pGameConf = NULL;
+
+char g_szMapEntities[2097152];
+
+CUtlVector *EntListeners()
+{
+ void *gEntList = gamehelpers->GetGlobalEntityList();
+ if (gEntList)
+ {
+ int offset = -1; /* 65572 */
+ if (g_pGameConf->GetOffset("EntityListeners", &offset))
+ {
+ return (CUtlVector *)((intptr_t) gEntList + offset);
+ }
+ }
+ else
+ {
+ void *entListeners;
+ if (g_pGameConf->GetAddress("EntityListenersPtr", &entListeners))
+ {
+ return (CUtlVector *)entListeners;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * IServerGameDLL & IVEngineServer Hooks
+ */
+SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, const char *, const char *, const char *, const char *, bool, bool);
+#ifdef GAMEDESC_CAN_CHANGE
+SH_DECL_HOOK0(IServerGameDLL, GetGameDescription, SH_NOATTRIB, 0, const char *);
+#endif
+SH_DECL_HOOK0(IVEngineServer, GetMapEntitiesString, SH_NOATTRIB, 0, const char *);
+
+
+/**
+ * CBaseEntity Hooks
+ */
+SH_DECL_MANUALHOOK1_void(EndTouch, 0, 0, 0, CBaseEntity *);
+SH_DECL_MANUALHOOK1_void(FireBullets, 0, 0, 0, FireBulletsInfo_t const&);
+#ifdef GETMAXHEALTH_IS_VIRTUAL
+SH_DECL_MANUALHOOK0(GetMaxHealth, 0, 0, 0, int);
+#endif
+SH_DECL_MANUALHOOK1_void(GroundEntChanged, 0, 0, 0, void *);
+SH_DECL_MANUALHOOK1(OnTakeDamage, 0, 0, 0, int, CTakeDamageInfoHack &);
+SH_DECL_MANUALHOOK1(OnTakeDamage_Alive, 0, 0, 0, int, CTakeDamageInfoHack &);
+SH_DECL_MANUALHOOK0_void(PreThink, 0, 0, 0);
+SH_DECL_MANUALHOOK0_void(PostThink, 0, 0, 0);
+SH_DECL_MANUALHOOK0(Reload, 0, 0, 0, bool);
+SH_DECL_MANUALHOOK2_void(SetTransmit, 0, 0, 0, CCheckTransmitInfo *, bool);
+SH_DECL_MANUALHOOK2(ShouldCollide, 0, 0, 0, bool, int, int);
+SH_DECL_MANUALHOOK0_void(Spawn, 0, 0, 0);
+SH_DECL_MANUALHOOK1_void(StartTouch, 0, 0, 0, CBaseEntity *);
+SH_DECL_MANUALHOOK0_void(Think, 0, 0, 0);
+SH_DECL_MANUALHOOK1_void(Touch, 0, 0, 0, CBaseEntity *);
+#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 \
+ || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_SDK2013
+SH_DECL_MANUALHOOK4_void(TraceAttack, 0, 0, 0, CTakeDamageInfoHack &, const Vector &, CGameTrace *, CDmgAccumulator *);
+#else
+SH_DECL_MANUALHOOK3_void(TraceAttack, 0, 0, 0, CTakeDamageInfoHack &, const Vector &, CGameTrace *);
+#endif
+SH_DECL_MANUALHOOK4_void(Use, 0, 0, 0, CBaseEntity *, CBaseEntity *, USE_TYPE, float);
+SH_DECL_MANUALHOOK1_void(VPhysicsUpdate, 0, 0, 0, IPhysicsObject *);
+SH_DECL_MANUALHOOK1(Weapon_CanSwitchTo, 0, 0, 0, bool, CBaseCombatWeapon *);
+SH_DECL_MANUALHOOK1(Weapon_CanUse, 0, 0, 0, bool, CBaseCombatWeapon *);
+SH_DECL_MANUALHOOK3_void(Weapon_Drop, 0, 0, 0, CBaseCombatWeapon *, const Vector *, const Vector *);
+SH_DECL_MANUALHOOK1_void(Weapon_Equip, 0, 0, 0, CBaseCombatWeapon *);
+SH_DECL_MANUALHOOK2(Weapon_Switch, 0, 0, 0, bool, CBaseCombatWeapon *, int);
+SH_DECL_MANUALHOOK1_void(Blocked, 0, 0, 0, CBaseEntity *);
+SH_DECL_MANUALHOOK0(CanBeAutobalanced, 0, 0, 0, bool);
+
+
+/**
+ * Forwards
+ */
+bool SDKHooks::SDK_OnLoad(char *error, size_t maxlength, bool late)
+{
+ char buffer[256];
+ g_pSM->BuildPath(Path_SM, buffer, sizeof(buffer)-1, "/extensions/sdkhooks.ext." PLATFORM_LIB_EXT);
+ if (libsys->PathExists(buffer) && libsys->IsPathFile(buffer))
+ {
+ g_pSM->Format(error, maxlength-1, "SDKHooks 2.x cannot load while old version (sdkhooks.ext." PLATFORM_LIB_EXT ") is still in extensions dir");
+ return false;
+ }
+
+ g_pSM->BuildPath(Path_SM, buffer, sizeof(buffer)-1, "/gamedata/sdkhooks.games.txt");
+ if (libsys->PathExists(buffer) && libsys->IsPathFile(buffer))
+ {
+ g_pSM->Format(error, maxlength-1, "SDKHooks 2.x cannot load while old gamedata file (sdkhooks.games.txt) is still in gamedata dir");
+ return false;
+ }
+
+ buffer[0] = '\0';
+ if (!gameconfs->LoadGameConfigFile("sdkhooks.games", &g_pGameConf, buffer, sizeof(buffer)))
+ {
+ if (buffer[0])
+ {
+ g_pSM->Format(error, maxlength, "Could not read sdkhooks.games gamedata: %s", buffer);
+ }
+
+ return false;
+ }
+
+ memset(m_EntityCache, INVALID_EHANDLE_INDEX, sizeof(m_EntityCache));
+
+ CUtlVector *entListeners = EntListeners();
+ if (!entListeners)
+ {
+ g_pSM->Format(error, maxlength, "Failed to setup entity listeners");
+ return false;
+ }
+
+ entListeners->AddToTail(this);
+
+ sharesys->AddDependency(myself, "bintools.ext", true, true);
+ sharesys->AddNatives(myself, g_Natives);
+ sharesys->RegisterLibrary(myself, "sdkhooks");
+ sharesys->AddInterface(myself, &g_Interface);
+ sharesys->AddCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD");
+ sharesys->AddCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport");
+
+ playerhelpers->AddClientListener(&g_Interface);
+
+ plsys->AddPluginsListener(&g_Interface);
+
+ g_pOnEntityCreated = forwards->CreateForward("OnEntityCreated", ET_Ignore, 2, NULL, Param_Cell, Param_String);
+ g_pOnEntityDestroyed = forwards->CreateForward("OnEntityDestroyed", ET_Ignore, 1, NULL, Param_Cell);
+#ifdef GAMEDESC_CAN_CHANGE
+ g_pOnGetGameNameDescription = forwards->CreateForward("OnGetGameDescription", ET_Hook, 2, NULL, Param_String);
+#endif
+ g_pOnLevelInit = forwards->CreateForward("OnLevelInit", ET_Hook, 2, NULL, Param_String, Param_String);
+
+ SetupHooks();
+
+#if SOURCE_ENGINE >= SE_ORANGEBOX
+ int index;
+ CBaseHandle hndl;
+ for (IHandleEntity *pEnt = (IHandleEntity *)servertools->FirstEntity(); pEnt; pEnt = (IHandleEntity *)servertools->NextEntity((CBaseEntity *)pEnt))
+ {
+ hndl = pEnt->GetRefEHandle();
+ if (!hndl.IsValid())
+ continue;
+
+ index = hndl.GetEntryIndex();
+ if (IsEntityIndexInRange(index))
+ {
+ m_EntityCache[index] = gamehelpers->IndexToReference(index);
+ }
+ else
+ {
+ g_pSM->LogError(myself, "SDKHooks::HandleEntityCreated - Got entity index out of range (%d)", index);
+ }
+ }
+#else
+ for (int i = 0; i < NUM_ENT_ENTRIES; i++)
+ {
+ if (gamehelpers->ReferenceToEntity(i) != NULL)
+ m_EntityCache[i] = gamehelpers->IndexToReference(i);
+ }
+#endif
+
+ return true;
+}
+
+inline void HookLevelInit()
+{
+ assert(g_hookOnLevelInit == 0);
+ g_hookOnLevelInit = SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(&g_Interface, &SDKHooks::Hook_LevelInit), false);
+ assert(g_hookOnGetMapEntitiesString == 0);
+ g_hookOnGetMapEntitiesString = SH_ADD_HOOK(IVEngineServer, GetMapEntitiesString, engine, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GetMapEntitiesString), false);
+}
+
+#ifdef GAMEDESC_CAN_CHANGE
+inline void HookGetGameDescription()
+{
+ assert(g_hookOnGetGameDescription == 0);
+ g_hookOnGetGameDescription = SH_ADD_HOOK(IServerGameDLL, GetGameDescription, gamedll, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GetGameDescription), false);
+}
+#endif
+
+void SDKHooks::SDK_OnAllLoaded()
+{
+ SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
+
+ if (!g_pBinTools)
+ {
+ g_pSM->LogError(myself, "Could not find interface: " SMINTERFACE_BINTOOLS_NAME);
+ return;
+ }
+
+ if (g_pOnLevelInit->GetFunctionCount() > 0)
+ HookLevelInit();
+#ifdef GAMEDESC_CAN_CHANGE
+ if (g_pOnGetGameNameDescription->GetFunctionCount() > 0)
+ HookGetGameDescription();
+#endif
+}
+
+#define KILL_HOOK_IF_ACTIVE(hook) \
+ if (hook != 0) \
+ { \
+ SH_REMOVE_HOOK_ID(hook); \
+ }
+
+void SDKHooks::SDK_OnUnload()
+{
+ // Remove left over hooks
+ Unhook(reinterpret_cast(NULL));
+
+ KILL_HOOK_IF_ACTIVE(g_hookOnLevelInit);
+ KILL_HOOK_IF_ACTIVE(g_hookOnGetMapEntitiesString);
+
+#ifdef GAMEDESC_CAN_CHANGE
+ KILL_HOOK_IF_ACTIVE(g_hookOnGetGameDescription);
+#endif
+
+ forwards->ReleaseForward(g_pOnEntityCreated);
+ forwards->ReleaseForward(g_pOnEntityDestroyed);
+#ifdef GAMEDESC_CAN_CHANGE
+ forwards->ReleaseForward(g_pOnGetGameNameDescription);
+#endif
+ forwards->ReleaseForward(g_pOnLevelInit);
+
+ plsys->RemovePluginsListener(&g_Interface);
+
+ playerhelpers->RemoveClientListener(&g_Interface);
+
+ sharesys->DropCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD");
+ sharesys->DropCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport");
+
+ CUtlVector *entListeners = EntListeners();
+ entListeners->FindAndRemove(this);
+
+ gameconfs->CloseGameConfigFile(g_pGameConf);
+}
+
+bool SDKHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
+{
+ GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
+
+#if SOURCE_ENGINE >= SE_ORANGEBOX
+ GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION);
+ g_pCVar = icvar;
+#endif
+ CONVAR_REGISTER(this);
+
+ gpGlobals = ismm->GetCGlobals();
+
+ return true;
+}
+
+const char *SDKHooks::GetExtensionVerString()
+{
+ return SOURCEMOD_VERSION;
+}
+
+const char *SDKHooks::GetExtensionDateString()
+{
+ return SOURCEMOD_BUILD_TIME;
+}
+
+void SDKHooks::OnPluginLoaded(IPlugin *plugin)
+{
+ if (g_pOnLevelInit->GetFunctionCount() > 0 && g_hookOnLevelInit == 0)
+ HookLevelInit();
+
+#ifdef GAMEDESC_CAN_CHANGE
+ if (g_pOnGetGameNameDescription->GetFunctionCount() > 0 && g_hookOnGetGameDescription == 0)
+ HookGetGameDescription();
+#endif
+}
+
+void SDKHooks::OnPluginUnloaded(IPlugin *plugin)
+{
+ Unhook(plugin->GetBaseContext());
+
+ if (g_pOnLevelInit->GetFunctionCount() == 0)
+ {
+ KILL_HOOK_IF_ACTIVE(g_hookOnLevelInit);
+ KILL_HOOK_IF_ACTIVE(g_hookOnGetMapEntitiesString);
+ }
+
+#ifdef GAMEDESC_CAN_CHANGE
+ if (g_pOnGetGameNameDescription->GetFunctionCount() == 0)
+ KILL_HOOK_IF_ACTIVE(g_hookOnGetGameDescription);
+#endif
+}
+
+void SDKHooks::OnClientPutInServer(int client)
+{
+ CBaseEntity *pPlayer = gamehelpers->ReferenceToEntity(client);
+
+ HandleEntityCreated(pPlayer, client, gamehelpers->EntityToReference(pPlayer));
+}
+
+void SDKHooks::OnClientDisconnecting(int client)
+{
+ CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(client);
+
+ HandleEntityDeleted(pEntity);
+}
+
+void SDKHooks::AddEntityListener(ISMEntityListener *listener)
+{
+ m_EntListeners.push_back(listener);
+}
+
+void SDKHooks::RemoveEntityListener(ISMEntityListener *listener)
+{
+ m_EntListeners.remove(listener);
+}
+
+bool SDKHooks::RegisterConCommandBase(ConCommandBase *pVar)
+{
+ /* Always call META_REGCVAR instead of going through the engine. */
+ return META_REGCVAR(pVar);
+}
+
+FeatureStatus SDKHooks::GetFeatureStatus(FeatureType type, const char *name)
+{
+ return FeatureStatus_Available;
+}
+
+/**
+ * Functions
+ */
+
+static void PopulateCallbackList(const ke::Vector &source, ke::Vector &destination, int entity)
+{
+ destination.ensure(8); /* Skip trivial allocations as AMTL uses length<<1. */
+ for (size_t iter = 0; iter < source.length(); ++iter)
+ {
+ if (source[iter].entity != entity)
+ {
+ continue;
+ }
+
+ destination.append(source[iter].callback);
+ }
+}
+
+cell_t SDKHooks::Call(int entity, SDKHookType type, int other)
+{
+ return Call(gamehelpers->ReferenceToEntity(entity), type, gamehelpers->ReferenceToEntity(other));
+}
+
+cell_t SDKHooks::Call(CBaseEntity *pEnt, SDKHookType type, int other)
+{
+ return Call(pEnt, type, gamehelpers->ReferenceToEntity(other));
+}
+
+cell_t SDKHooks::Call(CBaseEntity *pEnt, SDKHookType type, CBaseEntity *pOther)
+{
+ cell_t ret = Pl_Continue;
+
+ CVTableHook vhook(pEnt);
+ ke::Vector &vtablehooklist = g_HookList[type];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEnt);
+ int other = gamehelpers->EntityToBCompatRef(pOther);
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCell(other);
+
+ cell_t res;
+ callback->Execute(&res);
+ if(res > ret)
+ {
+ ret = res;
+ }
+ }
+
+ break;
+ }
+
+ return ret;
+}
+
+void SDKHooks::SetupHooks()
+{
+ int offset;
+
+ // gamedata pre post
+ // (pre is not necessarily a prehook, just named without "Post" appeneded)
+
+ CHECKOFFSET(EndTouch, true, true);
+ CHECKOFFSET(FireBullets, false, true);
+ CHECKOFFSET(GroundEntChanged, false, true);
+ CHECKOFFSET(OnTakeDamage, true, true);
+ CHECKOFFSET(OnTakeDamage_Alive,true, true);
+ CHECKOFFSET(PreThink, true, true);
+ CHECKOFFSET(PostThink, true, true);
+ CHECKOFFSET(Reload, true, true);
+ CHECKOFFSET(SetTransmit, true, false);
+ CHECKOFFSET(ShouldCollide, true, false);
+ CHECKOFFSET(Spawn, true, true);
+ CHECKOFFSET(StartTouch, true, true);
+ CHECKOFFSET(Think, true, true);
+ CHECKOFFSET(Touch, true, true);
+ CHECKOFFSET(TraceAttack, true, true);
+ CHECKOFFSET(Use, true, true);
+ CHECKOFFSET_W(CanSwitchTo, true, true);
+ CHECKOFFSET_W(CanUse, true, true);
+ CHECKOFFSET_W(Drop, true, true);
+ CHECKOFFSET_W(Equip, true, true);
+ CHECKOFFSET_W(Switch, true, true);
+ CHECKOFFSET(VPhysicsUpdate, true, true);
+ CHECKOFFSET(Blocked, true, true);
+ CHECKOFFSET(CanBeAutobalanced, true, false);
+
+ // this one is in a class all its own -_-
+ offset = 0;
+ g_pGameConf->GetOffset("GroundEntChanged", &offset);
+ if (offset > 0)
+ {
+ SH_MANUALHOOK_RECONFIGURE(GroundEntChanged, offset, 0, 0);
+ g_HookTypes[SDKHook_GroundEntChangedPost].supported = true;
+ }
+
+#ifdef GETMAXHEALTH_IS_VIRTUAL
+ CHECKOFFSET(GetMaxHealth, true, false);
+#endif
+}
+
+HookReturn SDKHooks::Hook(int entity, SDKHookType type, IPluginFunction *callback)
+{
+ if(!g_HookTypes[type].supported)
+ return HookRet_NotSupported;
+
+ CBaseEntity *pEnt = gamehelpers->ReferenceToEntity(entity);
+ if(!pEnt)
+ return HookRet_InvalidEntity;
+ if(type < 0 || type >= SDKHook_MAXHOOKS)
+ return HookRet_InvalidHookType;
+
+ if (!!strcmp(g_HookTypes[type].dtReq, ""))
+ {
+ IServerUnknown *pUnk = (IServerUnknown *)pEnt;
+
+ IServerNetworkable *pNet = pUnk->GetNetworkable();
+ if (pNet && !UTIL_ContainsDataTable(pNet->GetServerClass()->m_pTable, g_HookTypes[type].dtReq))
+ return HookRet_BadEntForHookType;
+ }
+
+ size_t entry;
+ CVTableHook vhook(pEnt);
+ ke::Vector &vtablehooklist = g_HookList[type];
+ for (entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook == vtablehooklist[entry]->vtablehook)
+ {
+ break;
+ }
+ }
+
+ if (entry == vtablehooklist.length())
+ {
+ int hookid = 0;
+ switch(type)
+ {
+ case SDKHook_EndTouch:
+ hookid = SH_ADD_MANUALVPHOOK(EndTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_EndTouch), false);
+ break;
+ case SDKHook_EndTouchPost:
+ hookid = SH_ADD_MANUALVPHOOK(EndTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_EndTouchPost), true);
+ break;
+ case SDKHook_FireBulletsPost:
+ hookid = SH_ADD_MANUALVPHOOK(FireBullets, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_FireBulletsPost), true);
+ break;
+#ifdef GETMAXHEALTH_IS_VIRTUAL
+ case SDKHook_GetMaxHealth:
+ hookid = SH_ADD_MANUALVPHOOK(GetMaxHealth, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GetMaxHealth), false);
+ break;
+#endif
+ case SDKHook_GroundEntChangedPost:
+ hookid = SH_ADD_MANUALVPHOOK(GroundEntChanged, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_GroundEntChangedPost), true);
+ break;
+ case SDKHook_OnTakeDamage:
+ hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamage), false);
+ break;
+ case SDKHook_OnTakeDamagePost:
+ hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamagePost), true);
+ break;
+ case SDKHook_OnTakeDamage_Alive:
+ hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage_Alive, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamage_Alive), false);
+ break;
+ case SDKHook_OnTakeDamage_AlivePost:
+ hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage_Alive, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamage_AlivePost), true);
+ break;
+ case SDKHook_PreThink:
+ hookid = SH_ADD_MANUALVPHOOK(PreThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PreThink), false);
+ break;
+ case SDKHook_PreThinkPost:
+ hookid = SH_ADD_MANUALVPHOOK(PreThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PreThinkPost), true);
+ break;
+ case SDKHook_PostThink:
+ hookid = SH_ADD_MANUALVPHOOK(PostThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PostThink), false);
+ break;
+ case SDKHook_PostThinkPost:
+ hookid = SH_ADD_MANUALVPHOOK(PostThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PostThinkPost), true);
+ break;
+ case SDKHook_Reload:
+ hookid = SH_ADD_MANUALVPHOOK(Reload, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Reload), false);
+ break;
+ case SDKHook_ReloadPost:
+ hookid = SH_ADD_MANUALVPHOOK(Reload, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_ReloadPost), true);
+ break;
+ case SDKHook_SetTransmit:
+ hookid = SH_ADD_MANUALVPHOOK(SetTransmit, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_SetTransmit), false);
+ break;
+ case SDKHook_Spawn:
+ hookid = SH_ADD_MANUALVPHOOK(Spawn, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Spawn), false);
+ break;
+ case SDKHook_SpawnPost:
+ hookid = SH_ADD_MANUALVPHOOK(Spawn, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_SpawnPost), true);
+ break;
+ case SDKHook_StartTouch:
+ hookid = SH_ADD_MANUALVPHOOK(StartTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_StartTouch), false);
+ break;
+ case SDKHook_StartTouchPost:
+ hookid = SH_ADD_MANUALVPHOOK(StartTouch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_StartTouchPost), true);
+ break;
+ case SDKHook_Think:
+ hookid = SH_ADD_MANUALVPHOOK(Think, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Think), false);
+ break;
+ case SDKHook_ThinkPost:
+ hookid = SH_ADD_MANUALVPHOOK(Think, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_ThinkPost), true);
+ break;
+ case SDKHook_Touch:
+ hookid = SH_ADD_MANUALVPHOOK(Touch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Touch), false);
+ break;
+ case SDKHook_TouchPost:
+ hookid = SH_ADD_MANUALVPHOOK(Touch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_TouchPost), true);
+ break;
+ case SDKHook_TraceAttack:
+ hookid = SH_ADD_MANUALVPHOOK(TraceAttack, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_TraceAttack), false);
+ break;
+ case SDKHook_TraceAttackPost:
+ hookid = SH_ADD_MANUALVPHOOK(TraceAttack, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_TraceAttackPost), true);
+ break;
+ case SDKHook_Use:
+ hookid = SH_ADD_MANUALVPHOOK(Use, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Use), false);
+ break;
+ case SDKHook_UsePost:
+ hookid = SH_ADD_MANUALVPHOOK(Use, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_UsePost), true);
+ break;
+ case SDKHook_VPhysicsUpdate:
+ hookid = SH_ADD_MANUALVPHOOK(VPhysicsUpdate, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_VPhysicsUpdate), false);
+ break;
+ case SDKHook_VPhysicsUpdatePost:
+ hookid = SH_ADD_MANUALVPHOOK(VPhysicsUpdate, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_VPhysicsUpdatePost), true);
+ break;
+ case SDKHook_WeaponCanSwitchTo:
+ hookid = SH_ADD_MANUALVPHOOK(Weapon_CanSwitchTo, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanSwitchTo), false);
+ break;
+ case SDKHook_WeaponCanSwitchToPost:
+ hookid = SH_ADD_MANUALVPHOOK(Weapon_CanSwitchTo, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanSwitchToPost), true);
+ break;
+ case SDKHook_WeaponCanUse:
+ hookid = SH_ADD_MANUALVPHOOK(Weapon_CanUse, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanUse), false);
+ break;
+ case SDKHook_WeaponCanUsePost:
+ hookid = SH_ADD_MANUALVPHOOK(Weapon_CanUse, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponCanUsePost), true);
+ break;
+ case SDKHook_WeaponDrop:
+ hookid = SH_ADD_MANUALVPHOOK(Weapon_Drop, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponDrop), false);
+ break;
+ case SDKHook_WeaponDropPost:
+ hookid = SH_ADD_MANUALVPHOOK(Weapon_Drop, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponDropPost), true);
+ break;
+ case SDKHook_WeaponEquip:
+ hookid = SH_ADD_MANUALVPHOOK(Weapon_Equip, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponEquip), false);
+ break;
+ case SDKHook_WeaponEquipPost:
+ hookid = SH_ADD_MANUALVPHOOK(Weapon_Equip, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponEquipPost), true);
+ break;
+ case SDKHook_WeaponSwitch:
+ hookid = SH_ADD_MANUALVPHOOK(Weapon_Switch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponSwitch), false);
+ break;
+ case SDKHook_WeaponSwitchPost:
+ hookid = SH_ADD_MANUALVPHOOK(Weapon_Switch, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_WeaponSwitchPost), true);
+ break;
+ case SDKHook_ShouldCollide:
+ hookid = SH_ADD_MANUALVPHOOK(ShouldCollide, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_ShouldCollide), false);
+ break;
+ case SDKHook_Blocked:
+ hookid = SH_ADD_MANUALVPHOOK(Blocked, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Blocked), false);
+ break;
+ case SDKHook_BlockedPost:
+ hookid = SH_ADD_MANUALVPHOOK(Blocked, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_BlockedPost), true);
+ break;
+ case SDKHook_CanBeAutobalanced:
+ hookid = SH_ADD_MANUALVPHOOK(CanBeAutobalanced, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_CanBeAutobalanced), false);
+ break;
+ }
+
+ vhook.SetHookID(hookid);
+
+ CVTableList *vtablelist = new CVTableList;
+ vtablelist->vtablehook = new CVTableHook(vhook);
+ vtablehooklist.append(vtablelist);
+ }
+
+ // Add hook to hook list
+ HookList hook;
+ hook.entity = gamehelpers->EntityToBCompatRef(pEnt);
+ hook.callback = callback;
+ vtablehooklist[entry]->hooks.append(hook);
+
+ return HookRet_Successful;
+}
+
+void SDKHooks::Unhook(CBaseEntity *pEntity)
+{
+ if (pEntity == NULL)
+ {
+ return;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+ for (size_t type = 0; type < SDKHook_MAXHOOKS; ++type)
+ {
+ ke::Vector &vtablehooklist = g_HookList[type];
+ for (size_t listentry = 0; listentry < vtablehooklist.length(); ++listentry)
+ {
+ ke::Vector &pawnhooks = vtablehooklist[listentry]->hooks;
+ for (size_t entry = 0; entry < pawnhooks.length(); ++entry)
+ {
+ if (entity != pawnhooks[entry].entity)
+ {
+ continue;
+ }
+
+ pawnhooks.remove(entry--);
+ }
+
+ if (pawnhooks.length() == 0)
+ {
+ delete vtablehooklist[listentry];
+ vtablehooklist.remove(listentry--);
+ }
+ }
+ }
+}
+
+void SDKHooks::Unhook(IPluginContext *pContext)
+{
+ for (size_t type = 0; type < SDKHook_MAXHOOKS; ++type)
+ {
+ ke::Vector &vtablehooklist = g_HookList[type];
+ for (size_t listentry = 0; listentry < vtablehooklist.length(); ++listentry)
+ {
+ ke::Vector &pawnhooks = vtablehooklist[listentry]->hooks;
+ for (size_t entry = 0; entry < pawnhooks.length(); ++entry)
+ {
+ if (pContext != NULL && pContext != pawnhooks[entry].callback->GetParentRuntime()->GetDefaultContext())
+ {
+ continue;
+ }
+
+ pawnhooks.remove(entry--);
+ }
+
+ if (pawnhooks.length() == 0)
+ {
+ delete vtablehooklist[listentry];
+ vtablehooklist.remove(listentry--);
+ }
+ }
+ }
+}
+
+void SDKHooks::Unhook(int entity, SDKHookType type, IPluginFunction *pCallback)
+{
+ CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(entity);
+ if (pEntity == NULL)
+ {
+ return;
+ }
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[type];
+ for (size_t listentry = 0; listentry < vtablehooklist.length(); ++listentry)
+ {
+ if (vhook != vtablehooklist[listentry]->vtablehook)
+ {
+ continue;
+ }
+
+ entity = gamehelpers->EntityToBCompatRef(pEntity);
+
+ ke::Vector &pawnhooks = vtablehooklist[listentry]->hooks;
+ for (size_t entry = 0; entry < pawnhooks.length(); ++entry)
+ {
+ HookList &hookentry = pawnhooks[entry];
+ if (entity != hookentry.entity || pCallback != hookentry.callback)
+ {
+ continue;
+ }
+
+ pawnhooks.remove(entry--);
+ }
+
+ if (pawnhooks.length() == 0)
+ {
+ delete vtablehooklist[listentry];
+ vtablehooklist.remove(listentry);
+ }
+
+ break;
+ }
+}
+
+/**
+ * IEntityFactoryDictionary, IServerGameDLL & IVEngineServer Hook Handlers
+ */
+void SDKHooks::OnEntityCreated(CBaseEntity *pEntity)
+{
+ // Call OnEntityCreated forward
+ int ref = gamehelpers->EntityToReference(pEntity);
+ int index = gamehelpers->ReferenceToIndex(ref);
+
+ // This can be -1 for player ents before any players have connected
+ if ((unsigned)index == INVALID_EHANDLE_INDEX || (index > 0 && index <= playerhelpers->GetMaxClients()))
+ {
+ return;
+ }
+
+ if (!IsEntityIndexInRange(index))
+ {
+ g_pSM->LogError(myself, "SDKHooks::OnEntityCreated - Got entity index out of range (%d)", index);
+ return;
+ }
+
+ // The entity could already exist. The creation notifier fires twice for some paths
+ if (m_EntityCache[index] != ref)
+ {
+ HandleEntityCreated(pEntity, index, ref);
+ }
+}
+
+#ifdef GAMEDESC_CAN_CHANGE
+const char *SDKHooks::Hook_GetGameDescription()
+{
+ static char szGameDesc[64];
+ cell_t result = Pl_Continue;
+
+ g_pSM->Format(szGameDesc, sizeof(szGameDesc), "%s",
+ SH_CALL(gamedll, &IServerGameDLL::GetGameDescription)());
+
+ // Call OnGetGameDescription forward
+ g_pOnGetGameNameDescription->PushStringEx(szGameDesc, sizeof(szGameDesc), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
+ g_pOnGetGameNameDescription->Execute(&result);
+
+ if(result == Pl_Changed)
+ RETURN_META_VALUE(MRES_SUPERCEDE, szGameDesc);
+
+ RETURN_META_VALUE(MRES_IGNORED, NULL);
+}
+#endif
+
+const char *SDKHooks::Hook_GetMapEntitiesString()
+{
+ if(g_szMapEntities[0])
+ RETURN_META_VALUE(MRES_SUPERCEDE, g_szMapEntities);
+
+ RETURN_META_VALUE(MRES_IGNORED, NULL);
+}
+
+bool SDKHooks::Hook_LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
+{
+ strcpy(g_szMapEntities, pMapEntities);
+ cell_t result = Pl_Continue;
+
+ // Call OnLevelInit forward
+ g_pOnLevelInit->PushString(pMapName);
+ g_pOnLevelInit->PushStringEx(g_szMapEntities, sizeof(g_szMapEntities), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
+ g_pOnLevelInit->Execute(&result);
+
+ if(result == Pl_Changed)
+ RETURN_META_VALUE_NEWPARAMS(MRES_HANDLED, true, &IServerGameDLL::LevelInit, (pMapName, g_szMapEntities, pOldLevel, pLandmarkName, loadGame, background));
+
+ RETURN_META_VALUE(MRES_IGNORED, true);
+}
+
+
+/**
+ * CBaseEntity Hook Handlers
+ */
+bool SDKHooks::Hook_CanBeAutobalanced()
+{
+ CBaseEntity *pPlayer = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pPlayer);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_CanBeAutobalanced];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pPlayer);
+
+ bool origRet = SH_MCALL(pPlayer, CanBeAutobalanced)();
+ bool newRet = origRet;
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ cell_t res = origRet;
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCell(origRet);
+ callback->Execute(&res);
+
+ // Only update our new ret if different from original
+ // (so if multiple plugins returning different answers,
+ // the one(s) that changed it win)
+ if ((bool)res != origRet)
+ newRet = !origRet;
+ }
+
+ if (newRet != origRet)
+ RETURN_META_VALUE(MRES_SUPERCEDE, newRet);
+
+ break;
+ }
+
+ RETURN_META_VALUE(MRES_IGNORED, false);
+}
+
+void SDKHooks::Hook_EndTouch(CBaseEntity *pOther)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_EndTouch, pOther);
+ if(result >= Pl_Handled)
+ RETURN_META(MRES_SUPERCEDE);
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_EndTouchPost(CBaseEntity *pOther)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_EndTouchPost, pOther);
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_FireBulletsPost(const FireBulletsInfo_t &info)
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+
+ IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(entity);
+ if(!pPlayer)
+ RETURN_META(MRES_IGNORED);
+
+ IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
+ if(!pInfo)
+ RETURN_META(MRES_IGNORED);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_FireBulletsPost];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ const char *weapon = pInfo->GetWeaponName();
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCell(info.m_iShots);
+ callback->PushString(weapon?weapon:"");
+ callback->Execute(NULL);
+ }
+
+ break;
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+#ifdef GETMAXHEALTH_IS_VIRTUAL
+int SDKHooks::Hook_GetMaxHealth()
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+ int original_max = SH_MCALL(pEntity, GetMaxHealth)();
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_GetMaxHealth];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+
+ int new_max = original_max;
+
+ cell_t res = Pl_Continue;
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCellByRef(&new_max);
+ callback->Execute(&res);
+ }
+
+ if (res >= Pl_Changed)
+ RETURN_META_VALUE(MRES_SUPERCEDE, new_max);
+
+ break;
+ }
+
+ RETURN_META_VALUE(MRES_IGNORED, original_max);
+}
+#endif
+
+void SDKHooks::Hook_GroundEntChangedPost(void *pVar)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_GroundEntChangedPost);
+}
+
+int SDKHooks::HandleOnTakeDamageHook(CTakeDamageInfoHack &info, SDKHookType hookType)
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[hookType];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+ int attacker = info.GetAttacker();
+ int inflictor = info.GetInflictor();
+ float damage = info.GetDamage();
+ int damagetype = info.GetDamageType();
+ int weapon = info.GetWeapon();
+
+ Vector force = info.GetDamageForce();
+ cell_t damageForce[3] = { sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z) };
+
+ Vector pos = info.GetDamagePosition();
+ cell_t damagePosition[3] = { sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z) };
+
+ cell_t res, ret = Pl_Continue;
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCellByRef(&attacker);
+ callback->PushCellByRef(&inflictor);
+ callback->PushFloatByRef(&damage);
+ callback->PushCellByRef(&damagetype);
+ callback->PushCellByRef(&weapon);
+ callback->PushArray(damageForce, 3, SM_PARAM_COPYBACK);
+ callback->PushArray(damagePosition, 3, SM_PARAM_COPYBACK);
+ callback->PushCell(info.GetDamageCustom());
+ callback->Execute(&res);
+
+ if (res >= ret)
+ {
+ ret = res;
+ if (ret == Pl_Changed)
+ {
+ CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker);
+ if (!pEntAttacker && attacker != -1)
+ {
+ callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for attacker is invalid", attacker);
+ RETURN_META_VALUE(MRES_IGNORED, 0);
+ }
+ CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor);
+ if (!pEntInflictor && inflictor != -1)
+ {
+ callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for inflictor is invalid", inflictor);
+ RETURN_META_VALUE(MRES_IGNORED, 0);
+ }
+
+ info.SetAttacker(pEntAttacker);
+ info.SetInflictor(pEntInflictor);
+ info.SetDamage(damage);
+ info.SetDamageType(damagetype);
+ info.SetWeapon(gamehelpers->ReferenceToEntity(weapon));
+ info.SetDamageForce(
+ sp_ctof(damageForce[0]),
+ sp_ctof(damageForce[1]),
+ sp_ctof(damageForce[2]));
+ info.SetDamagePosition(
+ sp_ctof(damagePosition[0]),
+ sp_ctof(damagePosition[1]),
+ sp_ctof(damagePosition[2]));
+ }
+ }
+ }
+
+ if (ret >= Pl_Handled)
+ RETURN_META_VALUE(MRES_SUPERCEDE, 1);
+
+ if (ret == Pl_Changed)
+ RETURN_META_VALUE(MRES_HANDLED, 1);
+
+ break;
+ }
+
+ RETURN_META_VALUE(MRES_IGNORED, 0);
+}
+
+int SDKHooks::HandleOnTakeDamageHookPost(CTakeDamageInfoHack &info, SDKHookType hookType)
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[hookType];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCell(info.GetAttacker());
+ callback->PushCell(info.GetInflictor());
+ callback->PushFloat(info.GetDamage());
+ callback->PushCell(info.GetDamageType());
+ callback->PushCell(info.GetWeapon());
+
+ Vector force = info.GetDamageForce();
+ cell_t damageForce[3] = { sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z) };
+ callback->PushArray(damageForce, 3);
+
+ Vector pos = info.GetDamagePosition();
+ cell_t damagePosition[3] = { sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z) };
+ callback->PushArray(damagePosition, 3);
+
+ callback->PushCell(info.GetDamageCustom());
+
+ callback->Execute(NULL);
+ }
+
+ break;
+ }
+
+ RETURN_META_VALUE(MRES_IGNORED, 0);
+}
+
+int SDKHooks::Hook_OnTakeDamage(CTakeDamageInfoHack &info)
+{
+ return HandleOnTakeDamageHook(info, SDKHook_OnTakeDamage);
+}
+
+int SDKHooks::Hook_OnTakeDamagePost(CTakeDamageInfoHack &info)
+{
+ return HandleOnTakeDamageHookPost(info, SDKHook_OnTakeDamagePost);
+}
+
+int SDKHooks::Hook_OnTakeDamage_Alive(CTakeDamageInfoHack &info)
+{
+ return HandleOnTakeDamageHook(info, SDKHook_OnTakeDamage_Alive);
+}
+
+int SDKHooks::Hook_OnTakeDamage_AlivePost(CTakeDamageInfoHack &info)
+{
+ return HandleOnTakeDamageHookPost(info, SDKHook_OnTakeDamage_AlivePost);
+}
+
+void SDKHooks::Hook_PreThink()
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_PreThink);
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_PreThinkPost()
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_PreThinkPost);
+}
+
+void SDKHooks::Hook_PostThink()
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_PostThink);
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_PostThinkPost()
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_PostThinkPost);
+}
+
+bool SDKHooks::Hook_Reload()
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_Reload];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+ cell_t res = Pl_Continue;
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->Execute(&res);
+ }
+
+ if (res >= Pl_Handled)
+ RETURN_META_VALUE(MRES_SUPERCEDE, false);
+
+ break;
+ }
+
+ RETURN_META_VALUE(MRES_IGNORED, true);
+}
+
+bool SDKHooks::Hook_ReloadPost()
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_ReloadPost];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+ cell_t origreturn = META_RESULT_ORIG_RET(bool) ? 1 : 0;
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCell(origreturn);
+ callback->Execute(NULL);
+ }
+
+ break;
+ }
+
+ return true;
+}
+
+void SDKHooks::Hook_SetTransmit(CCheckTransmitInfo *pInfo, bool bAlways)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_SetTransmit, gamehelpers->IndexOfEdict(pInfo->m_pClientEnt));
+
+ if(result >= Pl_Handled)
+ RETURN_META(MRES_SUPERCEDE);
+
+ RETURN_META(MRES_IGNORED);
+}
+
+bool SDKHooks::Hook_ShouldCollide(int collisionGroup, int contentsMask)
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_ShouldCollide];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+ cell_t origRet = ((META_RESULT_STATUS >= MRES_OVERRIDE)?(META_RESULT_OVERRIDE_RET(bool)):(META_RESULT_ORIG_RET(bool))) ? 1 : 0;
+ cell_t res = 0;
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCell(collisionGroup);
+ callback->PushCell(contentsMask);
+ callback->PushCell(origRet);
+ callback->Execute(&res);
+ }
+
+ bool ret = false;
+ if (res != 0)
+ {
+ ret = true;
+ }
+
+ RETURN_META_VALUE(MRES_SUPERCEDE, ret);
+ }
+
+ RETURN_META_VALUE(MRES_IGNORED, true);
+}
+
+void SDKHooks::Hook_Spawn()
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_Spawn];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+ cell_t res = Pl_Continue;
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->Execute(&res);
+ }
+
+ if (res >= Pl_Handled)
+ RETURN_META(MRES_SUPERCEDE);
+
+ break;
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_SpawnPost()
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_SpawnPost);
+}
+
+void SDKHooks::Hook_StartTouch(CBaseEntity *pOther)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_StartTouch, pOther);
+ if(result >= Pl_Handled)
+ RETURN_META(MRES_SUPERCEDE);
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_StartTouchPost(CBaseEntity *pOther)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_StartTouchPost, pOther);
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_Think()
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_Think);
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_ThinkPost()
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_ThinkPost);
+}
+
+void SDKHooks::Hook_Touch(CBaseEntity *pOther)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_Touch, pOther);
+
+ if(result >= Pl_Handled)
+ RETURN_META(MRES_SUPERCEDE);
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_TouchPost(CBaseEntity *pOther)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_TouchPost, pOther);
+ RETURN_META(MRES_IGNORED);
+}
+
+#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 \
+ || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_SDK2013
+void SDKHooks::Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator)
+#else
+void SDKHooks::Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr)
+#endif
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_TraceAttack];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+ int attacker = info.GetAttacker();
+ int inflictor = info.GetInflictor();
+ float damage = info.GetDamage();
+ int damagetype = info.GetDamageType();
+ int ammotype = info.GetAmmoType();
+ cell_t res, ret = Pl_Continue;
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCellByRef(&attacker);
+ callback->PushCellByRef(&inflictor);
+ callback->PushFloatByRef(&damage);
+ callback->PushCellByRef(&damagetype);
+ callback->PushCellByRef(&ammotype);
+ callback->PushCell(ptr->hitbox);
+ callback->PushCell(ptr->hitgroup);
+ callback->Execute(&res);
+
+ if(res > ret)
+ {
+ ret = res;
+
+ if(ret == Pl_Changed)
+ {
+ CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker);
+ if(!pEntAttacker)
+ {
+ callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for attacker is invalid", attacker);
+ RETURN_META(MRES_IGNORED);
+ }
+ CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor);
+ if(!pEntInflictor)
+ {
+ callback->GetParentContext()->BlamePluginError(callback, "Callback-provided entity %d for inflictor is invalid", inflictor);
+ RETURN_META(MRES_IGNORED);
+ }
+
+ info.SetAttacker(pEntAttacker);
+ info.SetInflictor(pEntInflictor);
+ info.SetDamage(damage);
+ info.SetDamageType(damagetype);
+ info.SetAmmoType(ammotype);
+ }
+ }
+ }
+
+ if(ret >= Pl_Handled)
+ RETURN_META(MRES_SUPERCEDE);
+
+ if(ret == Pl_Changed)
+ RETURN_META(MRES_HANDLED);
+
+ break;
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 \
+ || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_SDK2013
+void SDKHooks::Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator)
+#else
+void SDKHooks::Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr)
+#endif
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_TraceAttackPost];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCell(info.GetAttacker());
+ callback->PushCell(info.GetInflictor());
+ callback->PushFloat(info.GetDamage());
+ callback->PushCell(info.GetDamageType());
+ callback->PushCell(info.GetAmmoType());
+ callback->PushCell(ptr->hitbox);
+ callback->PushCell(ptr->hitgroup);
+ callback->Execute(NULL);
+ }
+
+ break;
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_Use];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+ int activator = gamehelpers->EntityToBCompatRef(pActivator);
+ int caller = gamehelpers->EntityToBCompatRef(pCaller);
+ cell_t ret = Pl_Continue;
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCell(activator);
+ callback->PushCell(caller);
+ callback->PushCell(useType);
+ callback->PushFloat(value);
+ callback->Execute(&ret);
+ }
+
+ if (ret >= Pl_Handled)
+ RETURN_META(MRES_SUPERCEDE);
+
+ break;
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_UsePost(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
+{
+ CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
+
+ CVTableHook vhook(pEntity);
+ ke::Vector &vtablehooklist = g_HookList[SDKHook_UsePost];
+ for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
+ {
+ if (vhook != vtablehooklist[entry]->vtablehook)
+ {
+ continue;
+ }
+
+ int entity = gamehelpers->EntityToBCompatRef(pEntity);
+ int activator = gamehelpers->EntityToBCompatRef(pActivator);
+ int caller = gamehelpers->EntityToBCompatRef(pCaller);
+
+ ke::Vector callbackList;
+ PopulateCallbackList(vtablehooklist[entry]->hooks, callbackList, entity);
+ for (entry = 0; entry < callbackList.length(); ++entry)
+ {
+ IPluginFunction *callback = callbackList[entry];
+ callback->PushCell(entity);
+ callback->PushCell(activator);
+ callback->PushCell(caller);
+ callback->PushCell(useType);
+ callback->PushFloat(value);
+ callback->Execute(NULL);
+ }
+
+ break;
+ }
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::OnEntityDeleted(CBaseEntity *pEntity)
+{
+ int index = gamehelpers->ReferenceToIndex(gamehelpers->EntityToReference(pEntity));
+
+ // This can be -1 for player ents before any players have connected
+ if ((unsigned)index == INVALID_EHANDLE_INDEX || (index > 0 && index <= playerhelpers->GetMaxClients()))
+ {
+ return;
+ }
+
+ HandleEntityDeleted(pEntity);
+}
+
+void SDKHooks::Hook_VPhysicsUpdate(IPhysicsObject *pPhysics)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_VPhysicsUpdate);
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_VPhysicsUpdatePost(IPhysicsObject *pPhysics)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_VPhysicsUpdatePost);
+}
+
+void SDKHooks::Hook_Blocked(CBaseEntity *pOther)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_Blocked, pOther);
+
+ if(result >= Pl_Handled)
+ RETURN_META(MRES_SUPERCEDE);
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_BlockedPost(CBaseEntity *pOther)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_BlockedPost, pOther);
+ RETURN_META(MRES_IGNORED);
+}
+
+bool SDKHooks::Hook_WeaponCanSwitchTo(CBaseCombatWeapon *pWeapon)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanSwitchTo, pWeapon);
+
+ if(result >= Pl_Handled)
+ RETURN_META_VALUE(MRES_SUPERCEDE, false);
+
+ RETURN_META_VALUE(MRES_IGNORED, true);
+}
+
+bool SDKHooks::Hook_WeaponCanSwitchToPost(CBaseCombatWeapon *pWeapon)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanSwitchToPost, pWeapon);
+ RETURN_META_VALUE(MRES_IGNORED, true);
+}
+
+bool SDKHooks::Hook_WeaponCanUse(CBaseCombatWeapon *pWeapon)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanUse, pWeapon);
+
+ if(result >= Pl_Handled)
+ RETURN_META_VALUE(MRES_SUPERCEDE, false);
+
+ RETURN_META_VALUE(MRES_IGNORED, true);
+}
+
+bool SDKHooks::Hook_WeaponCanUsePost(CBaseCombatWeapon *pWeapon)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanUsePost, pWeapon);
+ RETURN_META_VALUE(MRES_IGNORED, true);
+}
+
+void SDKHooks::Hook_WeaponDrop(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponDrop, pWeapon);
+
+ if(result >= Pl_Handled)
+ RETURN_META(MRES_SUPERCEDE);
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_WeaponDropPost(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponDropPost, pWeapon);
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_WeaponEquip(CBaseCombatWeapon *pWeapon)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponEquip, pWeapon);
+
+ if(result >= Pl_Handled)
+ RETURN_META(MRES_SUPERCEDE);
+
+ RETURN_META(MRES_IGNORED);
+}
+
+void SDKHooks::Hook_WeaponEquipPost(CBaseCombatWeapon *pWeapon)
+{
+ Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponEquipPost, pWeapon);
+ RETURN_META(MRES_IGNORED);
+}
+
+bool SDKHooks::Hook_WeaponSwitch(CBaseCombatWeapon *pWeapon, int viewmodelindex)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponSwitch, pWeapon);
+
+ if(result >= Pl_Handled)
+ RETURN_META_VALUE(MRES_SUPERCEDE, false);
+
+ RETURN_META_VALUE(MRES_IGNORED, true);
+}
+
+bool SDKHooks::Hook_WeaponSwitchPost(CBaseCombatWeapon *pWeapon, int viewmodelindex)
+{
+ cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponSwitchPost, pWeapon);
+ RETURN_META_VALUE(MRES_IGNORED, true);
+}
+
+void SDKHooks::HandleEntityCreated(CBaseEntity *pEntity, int index, cell_t ref)
+{
+ const char *pName = gamehelpers->GetEntityClassname(pEntity);
+ cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity);
+
+ // Send OnEntityCreated to SM listeners
+ SourceHook::List::iterator iter;
+ ISMEntityListener *pListener = NULL;
+ for (iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++)
+ {
+ pListener = (*iter);
+ pListener->OnEntityCreated(pEntity, pName ? pName : "");
+ }
+
+ // Call OnEntityCreated forward
+ g_pOnEntityCreated->PushCell(bcompatRef);
+ g_pOnEntityCreated->PushString(pName ? pName : "");
+ g_pOnEntityCreated->Execute(NULL);
+
+ m_EntityCache[index] = ref;
+}
+
+void SDKHooks::HandleEntityDeleted(CBaseEntity *pEntity)
+{
+ cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity);
+
+ // Send OnEntityDestroyed to SM listeners
+ SourceHook::List::iterator iter;
+ ISMEntityListener *pListener = NULL;
+ for (iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++)
+ {
+ pListener = (*iter);
+ pListener->OnEntityDestroyed(pEntity);
+ }
+
+ // Call OnEntityDestroyed forward
+ g_pOnEntityDestroyed->PushCell(bcompatRef);
+ g_pOnEntityDestroyed->Execute(NULL);
+
+ Unhook(pEntity);
+}