extensions/sdkhooks/extension.cpp
changeset 3767 7223d0a452a8
child 3774 5f34f4ed1a4f
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/extensions/sdkhooks/extension.cpp	Thu Feb 07 23:43:33 2013 -0500
     1.3 @@ -0,0 +1,1534 @@
     1.4 +/**
     1.5 + * vim: set ts=4 :
     1.6 + * =============================================================================
     1.7 + * Source SDK Hooks Extension
     1.8 + * Copyright (C) 2010-2012 Nicholas Hastings
     1.9 + * Copyright (C) 2009-2010 Erik Minekus
    1.10 + * =============================================================================
    1.11 + *
    1.12 + * This program is free software; you can redistribute it and/or modify it under
    1.13 + * the terms of the GNU General Public License, version 3.0, as published by the
    1.14 + * Free Software Foundation.
    1.15 + * 
    1.16 + * This program is distributed in the hope that it will be useful, but WITHOUT
    1.17 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.18 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    1.19 + * details.
    1.20 + *
    1.21 + * You should have received a copy of the GNU General Public License along with
    1.22 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    1.23 + *
    1.24 + * As a special exception, AlliedModders LLC gives you permission to link the
    1.25 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    1.26 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    1.27 + * by the Valve Corporation.  You must obey the GNU General Public License in
    1.28 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    1.29 + * this exception to all derivative works.  AlliedModders LLC defines further
    1.30 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    1.31 + * or <http://www.sourcemod.net/license.php>.
    1.32 + *
    1.33 + * Version: $Id$
    1.34 + */
    1.35 +
    1.36 +#include "extension.h"
    1.37 +#include "compat_wrappers.h"
    1.38 +#include "macros.h"
    1.39 +#include "natives.h"
    1.40 +#include <sm_platform.h>
    1.41 +#include <const.h>
    1.42 +
    1.43 +
    1.44 +//#define SDKHOOKSDEBUG
    1.45 +
    1.46 +/**
    1.47 + * Globals
    1.48 + */
    1.49 +
    1.50 +// Order MUST match SDKHookType enum
    1.51 +HookTypeData g_HookTypes[SDKHook_MAXHOOKS] = 
    1.52 +{
    1.53 +//   Hook name                DT required               Supported (always false til later)
    1.54 +	{"EndTouch",              "",                       false},
    1.55 +	{"FireBulletsPost",       "",                       false},
    1.56 +	{"OnTakeDamage",          "",                       false},
    1.57 +	{"OnTakeDamagePost",      "",                       false},
    1.58 +	{"PreThink",              "DT_BasePlayer",          false},
    1.59 +	{"PostThink",             "DT_BasePlayer",          false},
    1.60 +	{"SetTransmit",           "",                       false},
    1.61 +	{"Spawn",                 "",                       false},
    1.62 +	{"StartTouch",            "",                       false},
    1.63 +	{"Think",                 "",                       false},
    1.64 +	{"Touch",                 "",                       false},
    1.65 +	{"TraceAttack",           "",                       false},
    1.66 +	{"TraceAttackPost",       "",                       false},
    1.67 +	{"WeaponCanSwitchTo",     "DT_BaseCombatCharacter", false},
    1.68 +	{"WeaponCanUse",          "DT_BaseCombatCharacter", false},
    1.69 +	{"WeaponDrop",            "DT_BaseCombatCharacter", false},
    1.70 +	{"WeaponEquip",           "DT_BaseCombatCharacter", false},
    1.71 +	{"WeaponSwitch",          "DT_BaseCombatCharacter", false},
    1.72 +	{"ShouldCollide",         "",                       false},
    1.73 +	{"PreThinkPost",          "DT_BasePlayer",          false},
    1.74 +	{"PostThinkPost",         "DT_BasePlayer",          false},
    1.75 +	{"ThinkPost",             "",                       false},
    1.76 +	{"EndTouchPost",          "",                       false},
    1.77 +	{"GroundEntChangedPost",  "",                       false},
    1.78 +	{"SpawnPost",             "",                       false},
    1.79 +	{"StartTouchPost",        "",                       false},
    1.80 +	{"TouchPost",             "",                       false},
    1.81 +	{"VPhysicsUpdate",        "",                       false},
    1.82 +	{"VPhysicsUpdatePost",    "",                       false},
    1.83 +	{"WeaponCanSwitchToPost", "DT_BaseCombatCharacter", false},
    1.84 +	{"WeaponCanUsePost",      "DT_BaseCombatCharacter", false},
    1.85 +	{"WeaponDropPost",        "DT_BaseCombatCharacter", false},
    1.86 +	{"WeaponEquipPost",       "DT_BaseCombatCharacter", false},
    1.87 +	{"WeaponSwitchPost",      "DT_BaseCombatCharacter", false},
    1.88 +	{"Use",                   "",                       false},
    1.89 +	{"UsePost",               "",                       false},
    1.90 +	{"Reload",                "DT_BaseCombatWeapon",    false},
    1.91 +	{"ReloadPost",            "DT_BaseCombatWeapon",    false},
    1.92 +	{"GetMaxHealth",          "",                       false},
    1.93 +};
    1.94 +
    1.95 +SDKHooks g_Interface;
    1.96 +SMEXT_LINK(&g_Interface);
    1.97 +
    1.98 +CGlobalVars *gpGlobals;
    1.99 +CUtlVector<HookList> g_HookList;
   1.100 +
   1.101 +CBitVec<NUM_ENT_ENTRIES> m_EntityExists;
   1.102 +
   1.103 +IBinTools *g_pBinTools = NULL;
   1.104 +ICvar *icvar = NULL;
   1.105 +
   1.106 +// global hooks and forwards
   1.107 +IForward *g_pOnEntityCreated = NULL;
   1.108 +IForward *g_pOnEntityDestroyed = NULL;
   1.109 +
   1.110 +#ifdef GAMEDESC_CAN_CHANGE
   1.111 +int g_hookOnGetGameDescription = 0;
   1.112 +IForward *g_pOnGetGameNameDescription = NULL;
   1.113 +#endif
   1.114 +
   1.115 +int g_hookOnGetMapEntitiesString = 0;
   1.116 +int g_hookOnLevelInit = 0;
   1.117 +IForward *g_pOnLevelInit = NULL;
   1.118 +
   1.119 +IGameConfig *g_pGameConf = NULL;
   1.120 +int g_SplineCount = 0;
   1.121 +
   1.122 +char g_szMapEntities[2097152];
   1.123 +
   1.124 +
   1.125 +/**
   1.126 + * IServerGameDLL & IVEngineServer Hooks
   1.127 + */
   1.128 +SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, const char *, const char *, const char *, const char *, bool, bool);
   1.129 +#ifdef GAMEDESC_CAN_CHANGE
   1.130 +SH_DECL_HOOK0(IServerGameDLL, GetGameDescription, SH_NOATTRIB, 0, const char *);
   1.131 +#endif
   1.132 +SH_DECL_HOOK0(IVEngineServer, GetMapEntitiesString, SH_NOATTRIB, 0, const char *);
   1.133 +
   1.134 +
   1.135 +/**
   1.136 + * CBaseEntity Hooks
   1.137 + */
   1.138 +SH_DECL_MANUALHOOK1_void(EndTouch, 0, 0, 0, CBaseEntity *);
   1.139 +SH_DECL_MANUALHOOK1_void(FireBullets, 0, 0, 0, FireBulletsInfo_t const&);
   1.140 +#ifdef GETMAXHEALTH_IS_VIRTUAL
   1.141 +SH_DECL_MANUALHOOK0(GetMaxHealth, 0, 0, 0, int);
   1.142 +#endif
   1.143 +SH_DECL_MANUALHOOK0_void(GroundEntChanged, 0, 0, 0);
   1.144 +SH_DECL_MANUALHOOK1(OnTakeDamage, 0, 0, 0, int, CTakeDamageInfoHack &);
   1.145 +SH_DECL_MANUALHOOK0_void(PreThink, 0, 0, 0);
   1.146 +SH_DECL_MANUALHOOK0_void(PostThink, 0, 0, 0);
   1.147 +SH_DECL_MANUALHOOK0(Reload, 0, 0, 0, bool);
   1.148 +SH_DECL_MANUALHOOK2_void(SetTransmit, 0, 0, 0, CCheckTransmitInfo *, bool);
   1.149 +SH_DECL_MANUALHOOK2(ShouldCollide, 0, 0, 0, bool, int, int);
   1.150 +SH_DECL_MANUALHOOK0_void(Spawn, 0, 0, 0);
   1.151 +SH_DECL_MANUALHOOK1_void(StartTouch, 0, 0, 0, CBaseEntity *);
   1.152 +SH_DECL_MANUALHOOK0_void(Think, 0, 0, 0);
   1.153 +SH_DECL_MANUALHOOK1_void(Touch, 0, 0, 0, CBaseEntity *);
   1.154 +#if SOURCE_ENGINE == SE_ORANGEBOXVALVE || SOURCE_ENGINE == SE_CSS
   1.155 +SH_DECL_MANUALHOOK4_void(TraceAttack, 0, 0, 0, CTakeDamageInfoHack &, const Vector &, CGameTrace *, void *);
   1.156 +#else
   1.157 +SH_DECL_MANUALHOOK3_void(TraceAttack, 0, 0, 0, CTakeDamageInfoHack &, const Vector &, CGameTrace *);
   1.158 +#endif
   1.159 +SH_DECL_MANUALHOOK4_void(Use, 0, 0, 0, CBaseEntity *, CBaseEntity *, USE_TYPE, float);
   1.160 +SH_DECL_MANUALHOOK1_void(VPhysicsUpdate, 0, 0, 0, IPhysicsObject *);
   1.161 +SH_DECL_MANUALHOOK1(Weapon_CanSwitchTo, 0, 0, 0, bool, CBaseCombatWeapon *);
   1.162 +SH_DECL_MANUALHOOK1(Weapon_CanUse, 0, 0, 0, bool, CBaseCombatWeapon *);
   1.163 +SH_DECL_MANUALHOOK3_void(Weapon_Drop, 0, 0, 0, CBaseCombatWeapon *, const Vector *, const Vector *);
   1.164 +SH_DECL_MANUALHOOK1_void(Weapon_Equip, 0, 0, 0, CBaseCombatWeapon *);
   1.165 +SH_DECL_MANUALHOOK2(Weapon_Switch, 0, 0, 0, bool, CBaseCombatWeapon *, int);
   1.166 +
   1.167 +
   1.168 +/**
   1.169 + * Forwards
   1.170 + */
   1.171 +bool SDKHooks::SDK_OnLoad(char *error, size_t maxlength, bool late)
   1.172 +{
   1.173 +	char buffer[256];
   1.174 +	g_pSM->BuildPath(Path_SM, buffer, sizeof(buffer)-1, "/extensions/sdkhooks.ext." PLATFORM_LIB_EXT);
   1.175 +	if (libsys->PathExists(buffer) && libsys->IsPathFile(buffer))
   1.176 +	{
   1.177 +		g_pSM->Format(error, maxlength-1, "SDKHooks 2.x cannot load while old version (sdkhooks.ext." PLATFORM_LIB_EXT ") is still in extensions dir");
   1.178 +		return false;
   1.179 +	}
   1.180 +
   1.181 +	g_pSM->BuildPath(Path_SM, buffer, sizeof(buffer)-1, "/gamedata/sdkhooks.games.txt");
   1.182 +	if (libsys->PathExists(buffer) && libsys->IsPathFile(buffer))
   1.183 +	{
   1.184 +		g_pSM->Format(error, maxlength-1, "SDKHooks 2.x cannot load while old gamedata file (sdkhooks.games.txt) is still in gamedata dir");
   1.185 +		return false;
   1.186 +	}
   1.187 +
   1.188 +	sharesys->AddDependency(myself, "bintools.ext", true, true);
   1.189 +	sharesys->AddNatives(myself, g_Natives);
   1.190 +	sharesys->RegisterLibrary(myself, "sdkhooks");
   1.191 +	sharesys->AddCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD");
   1.192 +	sharesys->AddCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport");
   1.193 +
   1.194 +	playerhelpers->AddClientListener(&g_Interface);
   1.195 +	
   1.196 +	plsys->AddPluginsListener(&g_Interface);
   1.197 +
   1.198 +	g_pOnEntityCreated = forwards->CreateForward("OnEntityCreated", ET_Ignore, 2, NULL, Param_Cell, Param_String);
   1.199 +	g_pOnEntityDestroyed = forwards->CreateForward("OnEntityDestroyed", ET_Ignore, 1, NULL, Param_Cell);
   1.200 +#ifdef GAMEDESC_CAN_CHANGE
   1.201 +	g_pOnGetGameNameDescription = forwards->CreateForward("OnGetGameDescription", ET_Hook, 2, NULL, Param_String);
   1.202 +#endif
   1.203 +	g_pOnLevelInit = forwards->CreateForward("OnLevelInit", ET_Hook, 2, NULL, Param_String, Param_String);
   1.204 +
   1.205 +	buffer[0] = '\0';
   1.206 +	if (!gameconfs->LoadGameConfigFile("sdkhooks.games", &g_pGameConf, buffer, sizeof(buffer)))
   1.207 +	{
   1.208 +		if (buffer[0])
   1.209 +		{
   1.210 +			g_pSM->Format(error, maxlength, "Could not read sdkhooks.games gamedata: %s", buffer);
   1.211 +		}
   1.212 +		
   1.213 +		return false;
   1.214 +	}
   1.215 +
   1.216 +	void *gEntList = gamehelpers->GetGlobalEntityList();
   1.217 +	if (!gEntList)
   1.218 +	{
   1.219 +		g_pSM->Format(error, maxlength, "Cannot find gEntList pointer");
   1.220 +		return false;
   1.221 +	}
   1.222 +
   1.223 +	int offset = -1; /* 65572 */
   1.224 +	if (!g_pGameConf->GetOffset("EntityListeners", &offset))
   1.225 +	{
   1.226 +		g_pSM->Format(error, maxlength, "Cannot find EntityListeners offset");
   1.227 +		return false;
   1.228 +	}
   1.229 +
   1.230 +	CUtlVector<IEntityListener *> *pListeners = (CUtlVector<IEntityListener *> *)((intptr_t)gEntList + offset);
   1.231 +	pListeners->AddToTail(this);
   1.232 +
   1.233 +	SetupHooks();
   1.234 +
   1.235 +#if SOURCE_ENGINE >= SE_ORANGEBOX
   1.236 +	int index;
   1.237 +	CBaseHandle hndl;
   1.238 +	for (IHandleEntity *pEnt = (IHandleEntity *)servertools->FirstEntity(); pEnt; pEnt = (IHandleEntity *)servertools->NextEntity((CBaseEntity *)pEnt))
   1.239 +	{
   1.240 +		hndl = pEnt->GetRefEHandle();
   1.241 +		if (hndl == INVALID_EHANDLE_INDEX || !hndl.IsValid())
   1.242 +			continue;
   1.243 +		
   1.244 +		index = hndl.GetEntryIndex();
   1.245 +		m_EntityExists.Set(index);
   1.246 +	}
   1.247 +#else
   1.248 +	for (int i = 0; i < NUM_ENT_ENTRIES; i++)
   1.249 +	{
   1.250 +		if (gamehelpers->ReferenceToEntity(i) != NULL)
   1.251 +			m_EntityExists.Set(i);
   1.252 +	}
   1.253 +#endif
   1.254 +
   1.255 +	return true;
   1.256 +}
   1.257 +
   1.258 +inline void HookLevelInit()
   1.259 +{
   1.260 +	assert(g_hookOnLevelInit == 0);
   1.261 +	g_hookOnLevelInit = SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, &g_Interface, &SDKHooks::Hook_LevelInit, false);
   1.262 +	assert(g_hookOnGetMapEntitiesString == 0);
   1.263 +	g_hookOnGetMapEntitiesString = SH_ADD_HOOK_MEMFUNC(IVEngineServer, GetMapEntitiesString, engine, &g_Interface, &SDKHooks::Hook_GetMapEntitiesString, false);
   1.264 +}
   1.265 +
   1.266 +#ifdef GAMEDESC_CAN_CHANGE
   1.267 +inline void HookGetGameDescription()
   1.268 +{
   1.269 +	assert(g_hookOnGetGameDescription == 0);
   1.270 +	g_hookOnGetGameDescription = SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GetGameDescription, gamedll, &g_Interface, &SDKHooks::Hook_GetGameDescription, false);
   1.271 +}
   1.272 +#endif
   1.273 +
   1.274 +void SDKHooks::SDK_OnAllLoaded()
   1.275 +{
   1.276 +	SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
   1.277 +
   1.278 +	if (!g_pBinTools)
   1.279 +	{
   1.280 +		g_pSM->LogError(myself, "Could not find interface: " SMINTERFACE_BINTOOLS_NAME);
   1.281 +		return;
   1.282 +	}
   1.283 +
   1.284 +	if (g_pOnLevelInit->GetFunctionCount() > 0)
   1.285 +		HookLevelInit();
   1.286 +#ifdef GAMEDESC_CAN_CHANGE
   1.287 +	if (g_pOnGetGameNameDescription->GetFunctionCount() > 0)
   1.288 +		HookGetGameDescription();
   1.289 +#endif
   1.290 +}
   1.291 +
   1.292 +#define KILL_HOOK_IF_ACTIVE(hook) \
   1.293 +	if (hook != 0) \
   1.294 +	{ \
   1.295 +		SH_REMOVE_HOOK_ID(hook); \
   1.296 +	}
   1.297 +
   1.298 +void SDKHooks::SDK_OnUnload()
   1.299 +{
   1.300 +	// Remove left over hooks
   1.301 +	HOOKLOOP
   1.302 +		Unhook(i);
   1.303 +
   1.304 +	KILL_HOOK_IF_ACTIVE(g_hookOnLevelInit);
   1.305 +	KILL_HOOK_IF_ACTIVE(g_hookOnGetMapEntitiesString);
   1.306 +
   1.307 +#ifdef GAMEDESC_CAN_CHANGE
   1.308 +	KILL_HOOK_IF_ACTIVE(g_hookOnGetGameDescription);
   1.309 +#endif
   1.310 +
   1.311 +	forwards->ReleaseForward(g_pOnEntityCreated);
   1.312 +	forwards->ReleaseForward(g_pOnEntityDestroyed);
   1.313 +#ifdef GAMEDESC_CAN_CHANGE
   1.314 +	forwards->ReleaseForward(g_pOnGetGameNameDescription);
   1.315 +#endif
   1.316 +	forwards->ReleaseForward(g_pOnLevelInit);
   1.317 +
   1.318 +	plsys->RemovePluginsListener(&g_Interface);
   1.319 +
   1.320 +	playerhelpers->RemoveClientListener(&g_Interface);
   1.321 +
   1.322 +	sharesys->DropCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD");
   1.323 +	sharesys->DropCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport");
   1.324 +
   1.325 +	void *gEntList = gamehelpers->GetGlobalEntityList();
   1.326 +	if (gEntList)
   1.327 +	{
   1.328 +		int offset = -1; /* 65572 */
   1.329 +		if (g_pGameConf->GetOffset("EntityListeners", &offset))
   1.330 +		{
   1.331 +			CUtlVector<IEntityListener *> *pListeners = (CUtlVector<IEntityListener *> *)((intptr_t)gEntList + offset);
   1.332 +			pListeners->FindAndRemove(this);
   1.333 +		}
   1.334 +	}
   1.335 +
   1.336 +	gameconfs->CloseGameConfigFile(g_pGameConf);
   1.337 +}
   1.338 +
   1.339 +bool SDKHooks::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
   1.340 +{
   1.341 +	GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
   1.342 +
   1.343 +#if SOURCE_ENGINE >= SE_ORANGEBOX
   1.344 +	g_pCVar = icvar;
   1.345 +#endif
   1.346 +	CONVAR_REGISTER(this);
   1.347 +	
   1.348 +	gpGlobals = ismm->GetCGlobals();
   1.349 +
   1.350 +	return true;
   1.351 +}
   1.352 +
   1.353 +void SDKHooks::OnPluginLoaded(IPlugin *plugin)
   1.354 +{
   1.355 +	if (g_pOnLevelInit->GetFunctionCount() > 0 && g_hookOnLevelInit == 0)
   1.356 +		HookLevelInit();
   1.357 +
   1.358 +#ifdef GAMEDESC_CAN_CHANGE
   1.359 +	if (g_pOnGetGameNameDescription->GetFunctionCount() > 0 && g_hookOnGetGameDescription == 0)
   1.360 +		HookGetGameDescription();
   1.361 +#endif
   1.362 +}
   1.363 +
   1.364 +void SDKHooks::OnPluginUnloaded(IPlugin *plugin)
   1.365 +{
   1.366 +	IPluginContext *plugincontext = plugin->GetBaseContext();
   1.367 +	HOOKLOOP
   1.368 +	{
   1.369 +		if(g_HookList[i].callback->GetParentContext() == plugincontext)
   1.370 +			Unhook(i);
   1.371 +	}
   1.372 +
   1.373 +	if (g_pOnLevelInit->GetFunctionCount() == 0)
   1.374 +	{
   1.375 +		KILL_HOOK_IF_ACTIVE(g_hookOnLevelInit);
   1.376 +		KILL_HOOK_IF_ACTIVE(g_hookOnGetMapEntitiesString);
   1.377 +	}
   1.378 +
   1.379 +#ifdef GAMEDESC_CAN_CHANGE
   1.380 +	if (g_pOnGetGameNameDescription->GetFunctionCount() == 0)
   1.381 +		KILL_HOOK_IF_ACTIVE(g_hookOnGetGameDescription);
   1.382 +#endif
   1.383 +}
   1.384 +
   1.385 +void SDKHooks::OnClientPutInServer(int client)
   1.386 +{
   1.387 +	g_pOnEntityCreated->PushCell(client);
   1.388 +
   1.389 +	CBaseEntity *pPlayer = gamehelpers->ReferenceToEntity(client);
   1.390 +
   1.391 +	const char * pName = gamehelpers->GetEntityClassname(pPlayer);
   1.392 +
   1.393 +	g_pOnEntityCreated->PushString(pName ? pName : "");
   1.394 +	g_pOnEntityCreated->Execute(NULL);
   1.395 +
   1.396 +	m_EntityExists.Set(client);
   1.397 +}
   1.398 +
   1.399 +bool SDKHooks::RegisterConCommandBase(ConCommandBase *pVar)
   1.400 +{
   1.401 +	/* Always call META_REGCVAR instead of going through the engine. */
   1.402 +	return META_REGCVAR(pVar);
   1.403 +}
   1.404 +
   1.405 +FeatureStatus SDKHooks::GetFeatureStatus(FeatureType type, const char *name)
   1.406 +{
   1.407 +	return FeatureStatus_Available;
   1.408 +}
   1.409 +
   1.410 +/**
   1.411 + * Functions
   1.412 + */
   1.413 +cell_t SDKHooks::Call(int entity, SDKHookType type, int other)
   1.414 +{
   1.415 +	IPluginFunction *callback = NULL;
   1.416 +	cell_t res, ret = Pl_Continue;
   1.417 +
   1.418 +	HOOKLOOP
   1.419 +	{
   1.420 +		if(g_HookList[i].entity != entity || g_HookList[i].type != type)
   1.421 +			continue;
   1.422 +
   1.423 +		callback = g_HookList[i].callback;
   1.424 +		callback->PushCell(entity);
   1.425 +		if(other > -2)
   1.426 +			callback->PushCell(other);
   1.427 +
   1.428 +		callback->Execute(&res);
   1.429 +		if(res > ret)
   1.430 +			ret = res;
   1.431 +	}
   1.432 +
   1.433 +	return ret;
   1.434 +}
   1.435 +
   1.436 +cell_t SDKHooks::Call(CBaseEntity *pEnt, SDKHookType type, int other)
   1.437 +{
   1.438 +	return Call(gamehelpers->EntityToBCompatRef(pEnt), type, other);
   1.439 +}
   1.440 +
   1.441 +cell_t SDKHooks::Call(CBaseEntity *pEnt, SDKHookType type, CBaseEntity *other)
   1.442 +{
   1.443 +	return Call(gamehelpers->EntityToBCompatRef(pEnt), type, gamehelpers->EntityToBCompatRef(other));
   1.444 +}
   1.445 +
   1.446 +void SDKHooks::SetupHooks()
   1.447 +{
   1.448 +	int offset;
   1.449 +
   1.450 +	//			gamedata          pre    post
   1.451 +	// (pre is not necessarily a prehook, just named without "Post" appeneded)
   1.452 +
   1.453 +	CHECKOFFSET(EndTouch,         true,  true);
   1.454 +	CHECKOFFSET(FireBullets,      false, true);
   1.455 +	CHECKOFFSET(GroundEntChanged, false, true);
   1.456 +	CHECKOFFSET(OnTakeDamage,     true,  true);
   1.457 +	CHECKOFFSET(PreThink,         true,  true);
   1.458 +	CHECKOFFSET(PostThink,        true,  true);
   1.459 +	CHECKOFFSET(Reload,           true,  true);
   1.460 +	CHECKOFFSET(SetTransmit,      true,  false);
   1.461 +	CHECKOFFSET(ShouldCollide,    true,  false);
   1.462 +	CHECKOFFSET(Spawn,            true,  true);
   1.463 +	CHECKOFFSET(StartTouch,       true,  true);
   1.464 +	CHECKOFFSET(Think,            true,  true);
   1.465 +	CHECKOFFSET(Touch,            true,  true);
   1.466 +	CHECKOFFSET(TraceAttack,      true,  true);
   1.467 +	CHECKOFFSET(Use,              true,  true);
   1.468 +	CHECKOFFSET_W(CanSwitchTo,    true,  true);
   1.469 +	CHECKOFFSET_W(CanUse,         true,  true);
   1.470 +	CHECKOFFSET_W(Drop,           true,  true);
   1.471 +	CHECKOFFSET_W(Equip,          true,  true);
   1.472 +	CHECKOFFSET_W(Switch,         true,  true);
   1.473 +	CHECKOFFSET(VPhysicsUpdate,   true,  true);
   1.474 +
   1.475 +	// this one is in a class all its own -_-
   1.476 +	offset = 0;
   1.477 +	g_pGameConf->GetOffset("GroundEntChanged", &offset);
   1.478 +	if (offset > 0)
   1.479 +	{
   1.480 +		SH_MANUALHOOK_RECONFIGURE(GroundEntChanged, offset, 0, 0);
   1.481 +		g_HookTypes[SDKHook_GroundEntChangedPost].supported = true;
   1.482 +	}
   1.483 +
   1.484 +#ifdef GETMAXHEALTH_IS_VIRTUAL
   1.485 +	CHECKOFFSET(GetMaxHealth,	true,	false);
   1.486 +#endif
   1.487 +}
   1.488 +
   1.489 +HookReturn SDKHooks::Hook(int entity, SDKHookType type, IPluginFunction *callback)
   1.490 +{
   1.491 +	if(!g_HookTypes[type].supported)
   1.492 +		return HookRet_NotSupported;
   1.493 +
   1.494 +	CBaseEntity *pEnt = UTIL_GetCBaseEntity(entity);
   1.495 +	if(!pEnt)
   1.496 +		return HookRet_InvalidEntity;
   1.497 +	if(type < 0 || type >= SDKHook_MAXHOOKS)
   1.498 +		return HookRet_InvalidHookType;
   1.499 +
   1.500 +#if SOURCE_ENGINE >= SE_CSS
   1.501 +	if(entity > 0 && entity <= playerhelpers->GetMaxClients())
   1.502 +	{
   1.503 +		const char *id = engine->GetPlayerNetworkIDString(PEntityOfEntIndex(entity));
   1.504 +		g_SplineCount = strlen(id);
   1.505 +	}
   1.506 +#endif
   1.507 +
   1.508 +	if (!!strcmp(g_HookTypes[type].dtReq, ""))
   1.509 +	{
   1.510 +		sm_sendprop_info_t spi;
   1.511 +		IServerUnknown *pUnk = (IServerUnknown *)pEnt;
   1.512 +
   1.513 +		IServerNetworkable *pNet = pUnk->GetNetworkable();
   1.514 +		if (pNet && !UTIL_FindDataTable(pNet->GetServerClass()->m_pTable, g_HookTypes[type].dtReq, &spi, 0))
   1.515 +			return HookRet_BadEntForHookType;
   1.516 +	}
   1.517 +
   1.518 +	bool bHooked = false;
   1.519 +	HOOKLOOP
   1.520 +	{
   1.521 +		if (g_HookList[i].entity == entity && g_HookList[i].type == type)
   1.522 +		{
   1.523 +			bHooked = true;
   1.524 +			break;
   1.525 +		}
   1.526 +	}
   1.527 +	if (!bHooked)
   1.528 +	{
   1.529 +		switch(type)
   1.530 +		{
   1.531 +			case SDKHook_EndTouch:
   1.532 +				SH_ADD_MANUALHOOK_MEMFUNC(EndTouch, pEnt, &g_Interface, &SDKHooks::Hook_EndTouch, false);
   1.533 +				break;
   1.534 +			case SDKHook_EndTouchPost:
   1.535 +				SH_ADD_MANUALHOOK_MEMFUNC(EndTouch, pEnt, &g_Interface, &SDKHooks::Hook_EndTouchPost, true);
   1.536 +				break;
   1.537 +			case SDKHook_FireBulletsPost:
   1.538 +				SH_ADD_MANUALHOOK_MEMFUNC(FireBullets, pEnt, &g_Interface, &SDKHooks::Hook_FireBulletsPost, true);
   1.539 +				break;
   1.540 +#ifdef GETMAXHEALTH_IS_VIRTUAL
   1.541 +			case SDKHook_GetMaxHealth:
   1.542 +				SH_ADD_MANUALHOOK_MEMFUNC(GetMaxHealth, pEnt, &g_Interface, &SDKHooks::Hook_GetMaxHealth, false);
   1.543 +				break;
   1.544 +#endif
   1.545 +			case SDKHook_GroundEntChangedPost:
   1.546 +				SH_ADD_MANUALHOOK_MEMFUNC(GroundEntChanged, pEnt, &g_Interface, &SDKHooks::Hook_GroundEntChangedPost, true);
   1.547 +				break;
   1.548 +			case SDKHook_OnTakeDamage:
   1.549 +				SH_ADD_MANUALHOOK_MEMFUNC(OnTakeDamage, pEnt, &g_Interface, &SDKHooks::Hook_OnTakeDamage, false);
   1.550 +				break;
   1.551 +			case SDKHook_OnTakeDamagePost:
   1.552 +				SH_ADD_MANUALHOOK_MEMFUNC(OnTakeDamage, pEnt, &g_Interface, &SDKHooks::Hook_OnTakeDamagePost, true);
   1.553 +				break;
   1.554 +			case SDKHook_PreThink:
   1.555 +				SH_ADD_MANUALHOOK_MEMFUNC(PreThink, pEnt, &g_Interface, &SDKHooks::Hook_PreThink, false);
   1.556 +				break;
   1.557 +			case SDKHook_PreThinkPost:
   1.558 +				SH_ADD_MANUALHOOK_MEMFUNC(PreThink, pEnt, &g_Interface, &SDKHooks::Hook_PreThinkPost, true);
   1.559 +				break;
   1.560 +			case SDKHook_PostThink:
   1.561 +				SH_ADD_MANUALHOOK_MEMFUNC(PostThink, pEnt, &g_Interface, &SDKHooks::Hook_PostThink, false);
   1.562 +				break;
   1.563 +			case SDKHook_PostThinkPost:
   1.564 +				SH_ADD_MANUALHOOK_MEMFUNC(PostThink, pEnt, &g_Interface, &SDKHooks::Hook_PostThinkPost, true);
   1.565 +				break;
   1.566 +			case SDKHook_Reload:
   1.567 +				SH_ADD_MANUALHOOK_MEMFUNC(Reload, pEnt, &g_Interface, &SDKHooks::Hook_Reload, false);
   1.568 +				break;
   1.569 +			case SDKHook_ReloadPost:
   1.570 +				SH_ADD_MANUALHOOK_MEMFUNC(Reload, pEnt, &g_Interface, &SDKHooks::Hook_ReloadPost, true);
   1.571 +				break;
   1.572 +			case SDKHook_SetTransmit:
   1.573 +				SH_ADD_MANUALHOOK_MEMFUNC(SetTransmit, pEnt, &g_Interface, &SDKHooks::Hook_SetTransmit, false);
   1.574 +				break;
   1.575 +			case SDKHook_Spawn:
   1.576 +				SH_ADD_MANUALHOOK_MEMFUNC(Spawn, pEnt, &g_Interface, &SDKHooks::Hook_Spawn, false);
   1.577 +				break;
   1.578 +			case SDKHook_SpawnPost:
   1.579 +				SH_ADD_MANUALHOOK_MEMFUNC(Spawn, pEnt, &g_Interface, &SDKHooks::Hook_SpawnPost, true);
   1.580 +				break;
   1.581 +			case SDKHook_StartTouch:
   1.582 +				SH_ADD_MANUALHOOK_MEMFUNC(StartTouch, pEnt, &g_Interface, &SDKHooks::Hook_StartTouch, false);
   1.583 +				break;
   1.584 +			case SDKHook_StartTouchPost:
   1.585 +				SH_ADD_MANUALHOOK_MEMFUNC(StartTouch, pEnt, &g_Interface, &SDKHooks::Hook_StartTouchPost, true);
   1.586 +				break;
   1.587 +			case SDKHook_Think:
   1.588 +				SH_ADD_MANUALHOOK_MEMFUNC(Think, pEnt, &g_Interface, &SDKHooks::Hook_Think, false);
   1.589 +				break;
   1.590 +			case SDKHook_ThinkPost:
   1.591 +				SH_ADD_MANUALHOOK_MEMFUNC(Think, pEnt, &g_Interface, &SDKHooks::Hook_ThinkPost, true);
   1.592 +				break;
   1.593 +			case SDKHook_Touch:
   1.594 +				SH_ADD_MANUALHOOK_MEMFUNC(Touch, pEnt, &g_Interface, &SDKHooks::Hook_Touch, false);
   1.595 +				break;
   1.596 +			case SDKHook_TouchPost:
   1.597 +				SH_ADD_MANUALHOOK_MEMFUNC(Touch, pEnt, &g_Interface, &SDKHooks::Hook_TouchPost, true);
   1.598 +				break;
   1.599 +			case SDKHook_TraceAttack:
   1.600 +				SH_ADD_MANUALHOOK_MEMFUNC(TraceAttack, pEnt, &g_Interface, &SDKHooks::Hook_TraceAttack, false);
   1.601 +				break;
   1.602 +			case SDKHook_TraceAttackPost:
   1.603 +				SH_ADD_MANUALHOOK_MEMFUNC(TraceAttack, pEnt, &g_Interface, &SDKHooks::Hook_TraceAttackPost, true);
   1.604 +				break;
   1.605 +			case SDKHook_Use:
   1.606 +				SH_ADD_MANUALHOOK_MEMFUNC(Use, pEnt, &g_Interface, &SDKHooks::Hook_Use, false);
   1.607 +				break;
   1.608 +			case SDKHook_UsePost:
   1.609 +				SH_ADD_MANUALHOOK_MEMFUNC(Use, pEnt, &g_Interface, &SDKHooks::Hook_UsePost, true);
   1.610 +				break;
   1.611 +			case SDKHook_VPhysicsUpdate:
   1.612 +				SH_ADD_MANUALHOOK_MEMFUNC(VPhysicsUpdate, pEnt, &g_Interface, &SDKHooks::Hook_VPhysicsUpdate, false);
   1.613 +				break;
   1.614 +			case SDKHook_VPhysicsUpdatePost:
   1.615 +				SH_ADD_MANUALHOOK_MEMFUNC(VPhysicsUpdate, pEnt, &g_Interface, &SDKHooks::Hook_VPhysicsUpdatePost, true);
   1.616 +				break;
   1.617 +			case SDKHook_WeaponCanSwitchTo:
   1.618 +				SH_ADD_MANUALHOOK_MEMFUNC(Weapon_CanSwitchTo, pEnt, &g_Interface, &SDKHooks::Hook_WeaponCanSwitchTo, false);
   1.619 +				break;
   1.620 +			case SDKHook_WeaponCanSwitchToPost:
   1.621 +				SH_ADD_MANUALHOOK_MEMFUNC(Weapon_CanSwitchTo, pEnt, &g_Interface, &SDKHooks::Hook_WeaponCanSwitchToPost, true);
   1.622 +				break;
   1.623 +			case SDKHook_WeaponCanUse:
   1.624 +				SH_ADD_MANUALHOOK_MEMFUNC(Weapon_CanUse, pEnt, &g_Interface, &SDKHooks::Hook_WeaponCanUse, false);
   1.625 +				break;
   1.626 +			case SDKHook_WeaponCanUsePost:
   1.627 +				SH_ADD_MANUALHOOK_MEMFUNC(Weapon_CanUse, pEnt, &g_Interface, &SDKHooks::Hook_WeaponCanUsePost, true);
   1.628 +				break;
   1.629 +			case SDKHook_WeaponDrop:
   1.630 +				SH_ADD_MANUALHOOK_MEMFUNC(Weapon_Drop, pEnt, &g_Interface, &SDKHooks::Hook_WeaponDrop, false);
   1.631 +				break;
   1.632 +			case SDKHook_WeaponDropPost:
   1.633 +				SH_ADD_MANUALHOOK_MEMFUNC(Weapon_Drop, pEnt, &g_Interface, &SDKHooks::Hook_WeaponDropPost, true);
   1.634 +				break;
   1.635 +			case SDKHook_WeaponEquip:
   1.636 +				SH_ADD_MANUALHOOK_MEMFUNC(Weapon_Equip, pEnt, &g_Interface, &SDKHooks::Hook_WeaponEquip, false);
   1.637 +				break;
   1.638 +			case SDKHook_WeaponEquipPost:
   1.639 +				SH_ADD_MANUALHOOK_MEMFUNC(Weapon_Equip, pEnt, &g_Interface, &SDKHooks::Hook_WeaponEquipPost, true);
   1.640 +				break;
   1.641 +			case SDKHook_WeaponSwitch:
   1.642 +				SH_ADD_MANUALHOOK_MEMFUNC(Weapon_Switch, pEnt, &g_Interface, &SDKHooks::Hook_WeaponSwitch, false);
   1.643 +				break;
   1.644 +			case SDKHook_WeaponSwitchPost:
   1.645 +				SH_ADD_MANUALHOOK_MEMFUNC(Weapon_Switch, pEnt, &g_Interface, &SDKHooks::Hook_WeaponSwitchPost, true);
   1.646 +				break;
   1.647 +			case SDKHook_ShouldCollide:
   1.648 +				SH_ADD_MANUALHOOK_MEMFUNC(ShouldCollide, pEnt, &g_Interface, &SDKHooks::Hook_ShouldCollide, false);
   1.649 +				break;
   1.650 +		}
   1.651 +	}
   1.652 +
   1.653 +	// Add hook to hook list
   1.654 +	HookList hook;
   1.655 +	hook.entity = entity;
   1.656 +	hook.type = type;
   1.657 +	hook.callback = callback;
   1.658 +	g_HookList.AddToTail(hook);
   1.659 +#ifdef SDKHOOKSDEBUG
   1.660 +	META_CONPRINTF("DEBUG: Adding to hooklist (ent%d, type%s, cb%d). Total hook count %d\n", entity, g_szHookNames[type], callback, g_HookList.Count());
   1.661 +#endif
   1.662 +	return HookRet_Successful;
   1.663 +}
   1.664 +
   1.665 +void SDKHooks::Unhook(int index)
   1.666 +{
   1.667 +	CBaseEntity *pEnt = gamehelpers->ReferenceToEntity(g_HookList[index].entity);
   1.668 +	if(!pEnt)
   1.669 +		return;
   1.670 +
   1.671 +	int iHooks = 0;
   1.672 +	HOOKLOOP
   1.673 +	{
   1.674 +		if (g_HookList[i].entity == g_HookList[index].entity && g_HookList[i].type == g_HookList[index].type)
   1.675 +		{
   1.676 +			iHooks++;
   1.677 +#ifdef SDKHOOKSDEBUG
   1.678 +			META_CONPRINTF("DEBUG: Found hook %d on entity %d\n", i, g_HookList[index].entity);
   1.679 +#endif
   1.680 +		}
   1.681 +	}
   1.682 +	if (iHooks == 1)
   1.683 +	{
   1.684 +#ifdef SDKHOOKSDEBUG
   1.685 +		META_CONPRINTF("DEBUG: Removing hook for hooktype %d\n", g_HookList[index].type);
   1.686 +#endif
   1.687 +		switch(g_HookList[index].type)
   1.688 +		{
   1.689 +			case SDKHook_EndTouch:
   1.690 +				SH_REMOVE_MANUALHOOK_MEMFUNC(EndTouch, pEnt, &g_Interface, &SDKHooks::Hook_EndTouch, false);
   1.691 +				break;
   1.692 +			case SDKHook_EndTouchPost:
   1.693 +				SH_REMOVE_MANUALHOOK_MEMFUNC(EndTouch, pEnt, &g_Interface, &SDKHooks::Hook_EndTouchPost, true);
   1.694 +				break;
   1.695 +			case SDKHook_FireBulletsPost:
   1.696 +				SH_REMOVE_MANUALHOOK_MEMFUNC(FireBullets, pEnt, &g_Interface, &SDKHooks::Hook_FireBulletsPost, true);
   1.697 +				break;
   1.698 +#ifdef GETMAXHEALTH_IS_VIRTUAL
   1.699 +			case SDKHook_GetMaxHealth:
   1.700 +				SH_REMOVE_MANUALHOOK_MEMFUNC(GetMaxHealth, pEnt, &g_Interface, &SDKHooks::Hook_GetMaxHealth, false);
   1.701 +				break;
   1.702 +#endif
   1.703 +			case SDKHook_GroundEntChangedPost:
   1.704 +				SH_REMOVE_MANUALHOOK_MEMFUNC(GroundEntChanged, pEnt, &g_Interface, &SDKHooks::Hook_GroundEntChangedPost, true);
   1.705 +				break;
   1.706 +			case SDKHook_OnTakeDamage:
   1.707 +				SH_REMOVE_MANUALHOOK_MEMFUNC(OnTakeDamage, pEnt, &g_Interface, &SDKHooks::Hook_OnTakeDamage, false);
   1.708 +				break;
   1.709 +			case SDKHook_OnTakeDamagePost:
   1.710 +				SH_REMOVE_MANUALHOOK_MEMFUNC(OnTakeDamage, pEnt, &g_Interface, &SDKHooks::Hook_OnTakeDamagePost, true);
   1.711 +				break;
   1.712 +			case SDKHook_PreThink:
   1.713 +				SH_REMOVE_MANUALHOOK_MEMFUNC(PreThink, pEnt, &g_Interface, &SDKHooks::Hook_PreThink, false);
   1.714 +				break;
   1.715 +			case SDKHook_PreThinkPost:
   1.716 +				SH_REMOVE_MANUALHOOK_MEMFUNC(PreThink, pEnt, &g_Interface, &SDKHooks::Hook_PreThinkPost, true);
   1.717 +				break;
   1.718 +			case SDKHook_PostThink:
   1.719 +				SH_REMOVE_MANUALHOOK_MEMFUNC(PostThink, pEnt, &g_Interface, &SDKHooks::Hook_PostThink, false);
   1.720 +				break;
   1.721 +			case SDKHook_PostThinkPost:
   1.722 +				SH_REMOVE_MANUALHOOK_MEMFUNC(PostThink, pEnt, &g_Interface, &SDKHooks::Hook_PostThinkPost, true);
   1.723 +				break;
   1.724 +			case SDKHook_Reload:
   1.725 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Reload, pEnt, &g_Interface, &SDKHooks::Hook_Reload, false);
   1.726 +				break;
   1.727 +			case SDKHook_ReloadPost:
   1.728 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Reload, pEnt, &g_Interface, &SDKHooks::Hook_ReloadPost, true);
   1.729 +				break;
   1.730 +			case SDKHook_SetTransmit:
   1.731 +				SH_REMOVE_MANUALHOOK_MEMFUNC(SetTransmit, pEnt, &g_Interface, &SDKHooks::Hook_SetTransmit, false);
   1.732 +				break;
   1.733 +			case SDKHook_Spawn:
   1.734 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Spawn, pEnt, &g_Interface, &SDKHooks::Hook_Spawn, false);
   1.735 +				break;
   1.736 +			case SDKHook_SpawnPost:
   1.737 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Spawn, pEnt, &g_Interface, &SDKHooks::Hook_SpawnPost, true);
   1.738 +				break;
   1.739 +			case SDKHook_StartTouch:
   1.740 +				SH_REMOVE_MANUALHOOK_MEMFUNC(StartTouch, pEnt, &g_Interface, &SDKHooks::Hook_StartTouch, false);
   1.741 +				break;
   1.742 +			case SDKHook_StartTouchPost:
   1.743 +				SH_REMOVE_MANUALHOOK_MEMFUNC(StartTouch, pEnt, &g_Interface, &SDKHooks::Hook_StartTouchPost, true);
   1.744 +				break;
   1.745 +			case SDKHook_Think:
   1.746 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Think, pEnt, &g_Interface, &SDKHooks::Hook_Think, false);
   1.747 +				break;
   1.748 +			case SDKHook_ThinkPost:
   1.749 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Think, pEnt, &g_Interface, &SDKHooks::Hook_ThinkPost, true);
   1.750 +				break;
   1.751 +			case SDKHook_Touch:
   1.752 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Touch, pEnt, &g_Interface, &SDKHooks::Hook_Touch, false);
   1.753 +				break;
   1.754 +			case SDKHook_TouchPost:
   1.755 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Touch, pEnt, &g_Interface, &SDKHooks::Hook_TouchPost, true);
   1.756 +				break;
   1.757 +			case SDKHook_TraceAttack:
   1.758 +				SH_REMOVE_MANUALHOOK_MEMFUNC(TraceAttack, pEnt, &g_Interface, &SDKHooks::Hook_TraceAttack, false);
   1.759 +				break;
   1.760 +			case SDKHook_TraceAttackPost:
   1.761 +				SH_REMOVE_MANUALHOOK_MEMFUNC(TraceAttack, pEnt, &g_Interface, &SDKHooks::Hook_TraceAttackPost, true);
   1.762 +				break;
   1.763 +			case SDKHook_Use:
   1.764 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Use, pEnt, &g_Interface, &SDKHooks::Hook_Use, false);
   1.765 +				break;
   1.766 +			case SDKHook_UsePost:
   1.767 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Use, pEnt, &g_Interface, &SDKHooks::Hook_UsePost, true);
   1.768 +				break;
   1.769 +			case SDKHook_VPhysicsUpdate:
   1.770 +				SH_REMOVE_MANUALHOOK_MEMFUNC(VPhysicsUpdate, pEnt, &g_Interface, &SDKHooks::Hook_VPhysicsUpdate, false);
   1.771 +				break;
   1.772 +			case SDKHook_VPhysicsUpdatePost:
   1.773 +				SH_REMOVE_MANUALHOOK_MEMFUNC(VPhysicsUpdate, pEnt, &g_Interface, &SDKHooks::Hook_VPhysicsUpdatePost, true);
   1.774 +				break;
   1.775 +			case SDKHook_WeaponCanSwitchTo:
   1.776 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Weapon_CanSwitchTo, pEnt, &g_Interface, &SDKHooks::Hook_WeaponCanSwitchTo, false);
   1.777 +				break;
   1.778 +			case SDKHook_WeaponCanSwitchToPost:
   1.779 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Weapon_CanSwitchTo, pEnt, &g_Interface, &SDKHooks::Hook_WeaponCanSwitchToPost, true);
   1.780 +				break;
   1.781 +			case SDKHook_WeaponCanUse:
   1.782 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Weapon_CanUse, pEnt, &g_Interface, &SDKHooks::Hook_WeaponCanUse, false);
   1.783 +				break;
   1.784 +			case SDKHook_WeaponCanUsePost:
   1.785 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Weapon_CanUse, pEnt, &g_Interface, &SDKHooks::Hook_WeaponCanUsePost, true);
   1.786 +				break;
   1.787 +			case SDKHook_WeaponDrop:
   1.788 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Weapon_Drop, pEnt, &g_Interface, &SDKHooks::Hook_WeaponDrop, false);
   1.789 +				break;
   1.790 +			case SDKHook_WeaponDropPost:
   1.791 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Weapon_Drop, pEnt, &g_Interface, &SDKHooks::Hook_WeaponDropPost, true);
   1.792 +				break;
   1.793 +			case SDKHook_WeaponEquip:
   1.794 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Weapon_Equip, pEnt, &g_Interface, &SDKHooks::Hook_WeaponEquip, false);
   1.795 +				break;
   1.796 +			case SDKHook_WeaponEquipPost:
   1.797 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Weapon_Equip, pEnt, &g_Interface, &SDKHooks::Hook_WeaponEquipPost, true);
   1.798 +				break;
   1.799 +			case SDKHook_WeaponSwitch:
   1.800 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Weapon_Switch, pEnt, &g_Interface, &SDKHooks::Hook_WeaponSwitch, false);
   1.801 +				break;
   1.802 +			case SDKHook_WeaponSwitchPost:
   1.803 +				SH_REMOVE_MANUALHOOK_MEMFUNC(Weapon_Switch, pEnt, &g_Interface, &SDKHooks::Hook_WeaponSwitchPost, true);
   1.804 +				break;
   1.805 +			case SDKHook_ShouldCollide:
   1.806 +				SH_REMOVE_MANUALHOOK_MEMFUNC(ShouldCollide, pEnt, &g_Interface, &SDKHooks::Hook_ShouldCollide, false);
   1.807 +				break;
   1.808 +			default:
   1.809 +				return;
   1.810 +		}
   1.811 +	}
   1.812 +	g_HookList.Remove(index);
   1.813 +}
   1.814 +
   1.815 +
   1.816 +/**
   1.817 + * IEntityFactoryDictionary, IServerGameDLL & IVEngineServer Hook Handlers
   1.818 + */
   1.819 +void SDKHooks::OnEntityCreated(CBaseEntity *pEntity)
   1.820 +{
   1.821 +	// Call OnEntityCreated forward
   1.822 +	int entity = gamehelpers->ReferenceToIndex(gamehelpers->EntityToBCompatRef(pEntity));
   1.823 +	if (m_EntityExists.IsBitSet(entity) || (entity > 0 && entity <= playerhelpers->GetMaxClients()))
   1.824 +	{
   1.825 +		return;
   1.826 +	}
   1.827 +
   1.828 +	g_pOnEntityCreated->PushCell(gamehelpers->EntityToBCompatRef(pEntity));
   1.829 +
   1.830 +	const char * pName = gamehelpers->GetEntityClassname(pEntity);
   1.831 +	g_pOnEntityCreated->PushString(pName ? pName : "");
   1.832 +
   1.833 +	g_pOnEntityCreated->Execute(NULL);
   1.834 +
   1.835 +	m_EntityExists.Set(entity);
   1.836 +}
   1.837 +
   1.838 +#ifdef GAMEDESC_CAN_CHANGE
   1.839 +const char *SDKHooks::Hook_GetGameDescription()
   1.840 +{
   1.841 +	static char szGameDesc[64];
   1.842 +	cell_t result = Pl_Continue;
   1.843 +
   1.844 +	g_pSM->Format(szGameDesc, sizeof(szGameDesc), "%s",
   1.845 +		SH_CALL(gamedll, &IServerGameDLL::GetGameDescription)());
   1.846 +
   1.847 +	// Call OnGetGameDescription forward
   1.848 +	g_pOnGetGameNameDescription->PushStringEx(szGameDesc, sizeof(szGameDesc), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
   1.849 +	g_pOnGetGameNameDescription->Execute(&result);
   1.850 +
   1.851 +	if(result == Pl_Changed)
   1.852 +		RETURN_META_VALUE(MRES_SUPERCEDE, szGameDesc);
   1.853 +
   1.854 +	RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.855 +}
   1.856 +#endif
   1.857 +
   1.858 +const char *SDKHooks::Hook_GetMapEntitiesString()
   1.859 +{
   1.860 +	if(g_szMapEntities[0])
   1.861 +		RETURN_META_VALUE(MRES_SUPERCEDE, g_szMapEntities);
   1.862 +
   1.863 +	RETURN_META_VALUE(MRES_IGNORED, NULL);
   1.864 +}
   1.865 +
   1.866 +bool SDKHooks::Hook_LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
   1.867 +{
   1.868 +	strcpy(g_szMapEntities, pMapEntities);
   1.869 +	cell_t result = Pl_Continue;
   1.870 +
   1.871 +	// Call OnLevelInit forward
   1.872 +	g_pOnLevelInit->PushString(pMapName);
   1.873 +	g_pOnLevelInit->PushStringEx(g_szMapEntities, sizeof(g_szMapEntities), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
   1.874 +	g_pOnLevelInit->Execute(&result);
   1.875 +
   1.876 +	if(result >= Pl_Handled)
   1.877 +		RETURN_META_VALUE(MRES_SUPERCEDE, false);
   1.878 +
   1.879 +	if(result == Pl_Changed)
   1.880 +		RETURN_META_VALUE_NEWPARAMS(MRES_HANDLED, true, &IServerGameDLL::LevelInit, (pMapName, g_szMapEntities, pOldLevel, pLandmarkName, loadGame, background));
   1.881 +
   1.882 +	RETURN_META_VALUE(MRES_IGNORED, true);
   1.883 +}
   1.884 +
   1.885 +
   1.886 +/**
   1.887 + * CBaseEntity Hook Handlers
   1.888 + */
   1.889 +void SDKHooks::Hook_EndTouch(CBaseEntity *pOther)
   1.890 +{
   1.891 +	cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_EndTouch, pOther);
   1.892 +	if(result >= Pl_Handled)
   1.893 +		RETURN_META(MRES_SUPERCEDE);
   1.894 +
   1.895 +	RETURN_META(MRES_IGNORED);
   1.896 +}
   1.897 +
   1.898 +void SDKHooks::Hook_EndTouchPost(CBaseEntity *pOther)
   1.899 +{
   1.900 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_EndTouchPost, pOther);
   1.901 +	RETURN_META(MRES_IGNORED);
   1.902 +}
   1.903 +
   1.904 +void SDKHooks::Hook_FireBulletsPost(const FireBulletsInfo_t &info)
   1.905 +{
   1.906 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
   1.907 +
   1.908 +	IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(entity);
   1.909 +	if(!pPlayer)
   1.910 +		RETURN_META(MRES_IGNORED);
   1.911 +
   1.912 +	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   1.913 +	if(!pInfo)
   1.914 +		RETURN_META(MRES_IGNORED);
   1.915 +
   1.916 +	const char *weapon = pInfo->GetWeaponName();
   1.917 +	IPluginFunction *callback = NULL;
   1.918 +
   1.919 +	HOOKLOOP
   1.920 +	{
   1.921 +		if(g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_FireBulletsPost)
   1.922 +			continue;
   1.923 +
   1.924 +		callback = g_HookList[i].callback;
   1.925 +		callback->PushCell(entity);
   1.926 +		callback->PushCell(info.m_iShots);
   1.927 +		callback->PushString(weapon?weapon:"");
   1.928 +		callback->Execute(NULL);
   1.929 +	}
   1.930 +
   1.931 +	RETURN_META(MRES_IGNORED);
   1.932 +}
   1.933 +
   1.934 +#ifdef GETMAXHEALTH_IS_VIRTUAL
   1.935 +int SDKHooks::Hook_GetMaxHealth()
   1.936 +{
   1.937 +	CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
   1.938 +	int original_max = SH_MCALL(pEntity, GetMaxHealth)();
   1.939 +	int entity = gamehelpers->EntityToBCompatRef(pEntity);
   1.940 +
   1.941 +	int new_max = original_max;
   1.942 +
   1.943 +	cell_t res;
   1.944 +	IPluginFunction *callback = NULL;
   1.945 +
   1.946 +	HOOKLOOP
   1.947 +	{
   1.948 +		if (g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_GetMaxHealth)
   1.949 +			continue;
   1.950 +
   1.951 +		callback = g_HookList[i].callback;
   1.952 +		callback->PushCellByRef(&new_max);
   1.953 +		callback->Execute(&res);
   1.954 +	}
   1.955 +
   1.956 +	if (res >= Pl_Changed)
   1.957 +		RETURN_META_VALUE(MRES_SUPERCEDE, new_max);
   1.958 +
   1.959 +	RETURN_META_VALUE(MRES_IGNORED, original_max);
   1.960 +}
   1.961 +#endif
   1.962 +
   1.963 +void SDKHooks::Hook_GroundEntChangedPost()
   1.964 +{
   1.965 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_GroundEntChangedPost);
   1.966 +}
   1.967 +
   1.968 +int SDKHooks::Hook_OnTakeDamage(CTakeDamageInfoHack &info)
   1.969 +{
   1.970 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
   1.971 +	int attacker = info.GetAttacker();
   1.972 +	int inflictor = info.GetInflictor();
   1.973 +	float damage = info.GetDamage();
   1.974 +	int damagetype = info.GetDamageType();
   1.975 +	int weapon = info.GetWeapon();
   1.976 +
   1.977 +	Vector force = info.GetDamageForce();
   1.978 +	cell_t damageForce[3] = {sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z)};
   1.979 +
   1.980 +	Vector pos = info.GetDamagePosition();
   1.981 +	cell_t damagePosition[3] = {sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z)};
   1.982 +
   1.983 +	IPluginFunction *callback = NULL;
   1.984 +	cell_t res, ret = Pl_Continue;
   1.985 +
   1.986 +	HOOKLOOP
   1.987 +	{
   1.988 +		if(g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_OnTakeDamage)
   1.989 +			continue;
   1.990 +
   1.991 +		callback = g_HookList[i].callback;
   1.992 +		callback->PushCell(entity);
   1.993 +		callback->PushCellByRef(&attacker);
   1.994 +		callback->PushCellByRef(&inflictor);
   1.995 +		callback->PushFloatByRef(&damage);
   1.996 +		callback->PushCellByRef(&damagetype);
   1.997 +		callback->PushCellByRef(&weapon);
   1.998 +		callback->PushArray(damageForce, 3, SM_PARAM_COPYBACK);
   1.999 +		callback->PushArray(damagePosition, 3, SM_PARAM_COPYBACK);	
  1.1000 +		callback->PushCell(info.GetDamageCustom());
  1.1001 +		callback->Execute(&res);
  1.1002 +
  1.1003 +		if(res > ret)
  1.1004 +			ret = res;
  1.1005 +	}
  1.1006 +
  1.1007 +	if(ret >= Pl_Handled)
  1.1008 +		RETURN_META_VALUE(MRES_SUPERCEDE, 1);
  1.1009 +
  1.1010 +	if(ret == Pl_Changed)
  1.1011 +	{
  1.1012 +		CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker);
  1.1013 +		if(!pEntAttacker)
  1.1014 +		{
  1.1015 +			callback->GetParentContext()->ThrowNativeError("Entity %d for attacker is invalid", attacker);
  1.1016 +			RETURN_META_VALUE(MRES_IGNORED, 0);
  1.1017 +		}
  1.1018 +		CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor);
  1.1019 +		if(!pEntInflictor)
  1.1020 +		{
  1.1021 +			callback->GetParentContext()->ThrowNativeError("Entity %d for inflictor is invalid", inflictor);
  1.1022 +			RETURN_META_VALUE(MRES_IGNORED, 0);
  1.1023 +		}
  1.1024 +
  1.1025 +		info.SetAttacker(pEntAttacker);
  1.1026 +		info.SetInflictor(pEntInflictor);
  1.1027 +		info.SetDamage(damage);
  1.1028 +		info.SetDamageType(damagetype);
  1.1029 +		info.SetWeapon(gamehelpers->ReferenceToEntity(weapon));
  1.1030 +		info.SetDamageForce(
  1.1031 +			sp_ctof(damageForce[0]),
  1.1032 +			sp_ctof(damageForce[1]),
  1.1033 +			sp_ctof(damageForce[2]));
  1.1034 +		info.SetDamagePosition(
  1.1035 +			sp_ctof(damagePosition[0]),
  1.1036 +			sp_ctof(damagePosition[1]),
  1.1037 +			sp_ctof(damagePosition[2]));
  1.1038 +
  1.1039 +		RETURN_META_VALUE(MRES_HANDLED, 1); 
  1.1040 +	}
  1.1041 +
  1.1042 +	RETURN_META_VALUE(MRES_IGNORED, 0);
  1.1043 +}
  1.1044 +
  1.1045 +int SDKHooks::Hook_OnTakeDamagePost(CTakeDamageInfoHack &info)
  1.1046 +{
  1.1047 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
  1.1048 +	IPluginFunction *callback = NULL;
  1.1049 +
  1.1050 +	HOOKLOOP
  1.1051 +	{
  1.1052 +		if(g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_OnTakeDamagePost)
  1.1053 +			continue;
  1.1054 +
  1.1055 +		callback = g_HookList[i].callback;
  1.1056 +		callback->PushCell(entity);
  1.1057 +		callback->PushCell(info.GetAttacker());
  1.1058 +		callback->PushCell(info.GetInflictor());
  1.1059 +		callback->PushFloat(info.GetDamage());
  1.1060 +		callback->PushCell(info.GetDamageType());
  1.1061 +		callback->PushCell(info.GetWeapon());
  1.1062 +
  1.1063 +		Vector force = info.GetDamageForce();
  1.1064 +		cell_t damageForce[3] = {sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z)};
  1.1065 +		callback->PushArray(damageForce, 3);
  1.1066 +
  1.1067 +		Vector pos = info.GetDamagePosition();
  1.1068 +		cell_t damagePosition[3] = {sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z)};
  1.1069 +		callback->PushArray(damagePosition, 3);
  1.1070 +
  1.1071 +		callback->PushCell(info.GetDamageCustom());
  1.1072 +
  1.1073 +		callback->Execute(NULL);
  1.1074 +	}
  1.1075 +
  1.1076 +	RETURN_META_VALUE(MRES_IGNORED, 0);
  1.1077 +}
  1.1078 +
  1.1079 +void SDKHooks::Hook_PreThink()
  1.1080 +{
  1.1081 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_PreThink);
  1.1082 +}
  1.1083 +
  1.1084 +void SDKHooks::Hook_PreThinkPost()
  1.1085 +{
  1.1086 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_PreThinkPost);
  1.1087 +}
  1.1088 +
  1.1089 +void SDKHooks::Hook_PostThink()
  1.1090 +{
  1.1091 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_PostThink);
  1.1092 +}
  1.1093 +
  1.1094 +void SDKHooks::Hook_PostThinkPost()
  1.1095 +{
  1.1096 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_PostThinkPost);
  1.1097 +}
  1.1098 +
  1.1099 +bool SDKHooks::Hook_Reload()
  1.1100 +{
  1.1101 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
  1.1102 +	cell_t res;
  1.1103 +	IPluginFunction *callback = NULL;
  1.1104 +
  1.1105 +	HOOKLOOP
  1.1106 +	{
  1.1107 +		if (g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_Reload)
  1.1108 +			continue;
  1.1109 +
  1.1110 +		callback = g_HookList[i].callback;
  1.1111 +		callback->PushCell(entity);
  1.1112 +		callback->Execute(&res);
  1.1113 +	}
  1.1114 +
  1.1115 +	if (res >= Pl_Handled)
  1.1116 +		RETURN_META_VALUE(MRES_SUPERCEDE, false);
  1.1117 +
  1.1118 +	RETURN_META_VALUE(MRES_IGNORED, true);
  1.1119 +}
  1.1120 +
  1.1121 +bool SDKHooks::Hook_ReloadPost()
  1.1122 +{
  1.1123 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
  1.1124 +	IPluginFunction *callback = NULL;
  1.1125 +
  1.1126 +	HOOKLOOP
  1.1127 +	{
  1.1128 +		if (g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_ReloadPost)
  1.1129 +			continue;
  1.1130 +
  1.1131 +		callback = g_HookList[i].callback;
  1.1132 +		callback->PushCell(entity);
  1.1133 +		callback->PushCell(META_RESULT_OVERRIDE_RET(bool) ? 1 : 0);
  1.1134 +		callback->Execute(NULL);
  1.1135 +	}
  1.1136 +
  1.1137 +	return true;
  1.1138 +}
  1.1139 +
  1.1140 +void SDKHooks::Hook_SetTransmit(CCheckTransmitInfo *pInfo, bool bAlways)
  1.1141 +{
  1.1142 +	cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_SetTransmit, gamehelpers->IndexOfEdict(pInfo->m_pClientEnt));
  1.1143 +
  1.1144 +	if(result >= Pl_Handled)
  1.1145 +		RETURN_META(MRES_SUPERCEDE);
  1.1146 +
  1.1147 +	RETURN_META(MRES_IGNORED);
  1.1148 +}
  1.1149 +
  1.1150 +bool SDKHooks::Hook_ShouldCollide(int collisionGroup, int contentsMask)
  1.1151 +{
  1.1152 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
  1.1153 +	IPluginFunction *callback = NULL;
  1.1154 +	bool origRet = ((META_RESULT_STATUS >= MRES_OVERRIDE)?(META_RESULT_OVERRIDE_RET(bool)):(META_RESULT_ORIG_RET(bool)));
  1.1155 +	cell_t res;
  1.1156 +
  1.1157 +	HOOKLOOP
  1.1158 +	{
  1.1159 +		if (g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_ShouldCollide)
  1.1160 +			continue;
  1.1161 +
  1.1162 +		callback = g_HookList[i].callback;
  1.1163 +		callback->PushCell(entity);
  1.1164 +		callback->PushCell(collisionGroup);
  1.1165 +		callback->PushCell(contentsMask);
  1.1166 +		callback->PushCell(origRet ? 1 : 0);
  1.1167 +		callback->Execute(&res);
  1.1168 +	}
  1.1169 +
  1.1170 +	bool ret = false;
  1.1171 +	if (res != 0)
  1.1172 +	{
  1.1173 +		ret = true;
  1.1174 +	}
  1.1175 +
  1.1176 +	RETURN_META_VALUE(MRES_SUPERCEDE, ret);
  1.1177 +}
  1.1178 +
  1.1179 +void SDKHooks::Hook_Spawn()
  1.1180 +{
  1.1181 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
  1.1182 +	IPluginFunction *callback = NULL;
  1.1183 +	cell_t res;
  1.1184 +
  1.1185 +	HOOKLOOP
  1.1186 +	{
  1.1187 +		if (g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_Spawn)
  1.1188 +			continue;
  1.1189 +
  1.1190 +		callback = g_HookList[i].callback;
  1.1191 +		callback->PushCell(entity);
  1.1192 +		callback->Execute(&res);
  1.1193 +	}
  1.1194 +
  1.1195 +	if (res >= Pl_Handled)
  1.1196 +		RETURN_META(MRES_SUPERCEDE);
  1.1197 +
  1.1198 +	RETURN_META(MRES_IGNORED);
  1.1199 +}
  1.1200 +
  1.1201 +void SDKHooks::Hook_SpawnPost()
  1.1202 +{
  1.1203 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_SpawnPost);
  1.1204 +}
  1.1205 +
  1.1206 +void SDKHooks::Hook_StartTouch(CBaseEntity *pOther)
  1.1207 +{
  1.1208 +	cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_StartTouch, pOther);
  1.1209 +	if(result >= Pl_Handled)
  1.1210 +		RETURN_META(MRES_SUPERCEDE);
  1.1211 +
  1.1212 +	RETURN_META(MRES_IGNORED);
  1.1213 +}
  1.1214 +
  1.1215 +void SDKHooks::Hook_StartTouchPost(CBaseEntity *pOther)
  1.1216 +{
  1.1217 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_StartTouchPost, pOther);
  1.1218 +	RETURN_META(MRES_IGNORED);
  1.1219 +}
  1.1220 +
  1.1221 +void SDKHooks::Hook_Think()
  1.1222 +{
  1.1223 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_Think);
  1.1224 +}
  1.1225 +
  1.1226 +void SDKHooks::Hook_ThinkPost()
  1.1227 +{
  1.1228 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_ThinkPost);
  1.1229 +}
  1.1230 +
  1.1231 +void SDKHooks::Hook_Touch(CBaseEntity *pOther)
  1.1232 +{
  1.1233 +	cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_Touch, pOther);
  1.1234 +
  1.1235 +	if(result >= Pl_Handled)
  1.1236 +		RETURN_META(MRES_SUPERCEDE);
  1.1237 +
  1.1238 +	RETURN_META(MRES_IGNORED);
  1.1239 +}
  1.1240 +
  1.1241 +void SDKHooks::Hook_TouchPost(CBaseEntity *pOther)
  1.1242 +{
  1.1243 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_TouchPost, pOther);
  1.1244 +	RETURN_META(MRES_IGNORED);
  1.1245 +}
  1.1246 +
  1.1247 +#if SOURCE_ENGINE == SE_ORANGEBOXVALVE || SOURCE_ENGINE == SE_CSS
  1.1248 +void SDKHooks::Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, void *pUnknownJK)
  1.1249 +#else
  1.1250 +void SDKHooks::Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr)
  1.1251 +#endif
  1.1252 +{
  1.1253 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
  1.1254 +	int attacker = info.GetAttacker();
  1.1255 +	int inflictor = info.GetInflictor();
  1.1256 +	float damage = info.GetDamage();
  1.1257 +	int damagetype = info.GetDamageType();
  1.1258 +	int ammotype = info.GetAmmoType();
  1.1259 +	IPluginFunction *callback = NULL;
  1.1260 +	cell_t res, ret = Pl_Continue;
  1.1261 +
  1.1262 +	HOOKLOOP
  1.1263 +	{
  1.1264 +		if(g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_TraceAttack)
  1.1265 +			continue;
  1.1266 +
  1.1267 +		callback = g_HookList[i].callback;
  1.1268 +		callback->PushCell(entity);
  1.1269 +		callback->PushCellByRef(&attacker);
  1.1270 +		callback->PushCellByRef(&inflictor);
  1.1271 +		callback->PushFloatByRef(&damage);
  1.1272 +		callback->PushCellByRef(&damagetype);
  1.1273 +		callback->PushCellByRef(&ammotype);
  1.1274 +		callback->PushCell(ptr->hitbox);
  1.1275 +		callback->PushCell(ptr->hitgroup);
  1.1276 +		callback->Execute(&res);
  1.1277 +
  1.1278 +		if(res > ret)
  1.1279 +			ret = res;
  1.1280 +	}
  1.1281 +
  1.1282 +	if(ret >= Pl_Handled)
  1.1283 +		RETURN_META(MRES_SUPERCEDE);
  1.1284 +
  1.1285 +	if(ret == Pl_Changed)
  1.1286 +	{
  1.1287 +		CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker);
  1.1288 +		if(!pEntAttacker)
  1.1289 +		{
  1.1290 +			callback->GetParentContext()->ThrowNativeError("Entity %d for attacker is invalid", attacker);
  1.1291 +			RETURN_META(MRES_IGNORED);
  1.1292 +		}
  1.1293 +		CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor);
  1.1294 +		if(!pEntInflictor)
  1.1295 +		{
  1.1296 +			callback->GetParentContext()->ThrowNativeError("Entity %d for inflictor is invalid", inflictor);
  1.1297 +			RETURN_META(MRES_IGNORED);
  1.1298 +		}
  1.1299 +		
  1.1300 +		info.SetAttacker(gamehelpers->ReferenceToEntity(attacker));
  1.1301 +		info.SetInflictor(gamehelpers->ReferenceToEntity(inflictor));
  1.1302 +		info.SetDamage(damage);
  1.1303 +		info.SetDamageType(damagetype);
  1.1304 +		info.SetAmmoType(ammotype);
  1.1305 +
  1.1306 +		RETURN_META(MRES_HANDLED); 
  1.1307 +	}
  1.1308 +
  1.1309 +	RETURN_META(MRES_IGNORED);
  1.1310 +}
  1.1311 +
  1.1312 +#if SOURCE_ENGINE == SE_ORANGEBOXVALVE || SOURCE_ENGINE == SE_CSS
  1.1313 +void SDKHooks::Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, void *pUnknownJK)
  1.1314 +#else
  1.1315 +void SDKHooks::Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr)
  1.1316 +#endif
  1.1317 +{
  1.1318 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
  1.1319 +	IPluginFunction *callback = NULL;
  1.1320 +
  1.1321 +	HOOKLOOP
  1.1322 +	{
  1.1323 +		if(g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_TraceAttackPost)
  1.1324 +			continue;
  1.1325 +
  1.1326 +		callback = g_HookList[i].callback;
  1.1327 +		callback->PushCell(entity);
  1.1328 +		callback->PushCell(info.GetAttacker());
  1.1329 +		callback->PushCell(info.GetInflictor());
  1.1330 +		callback->PushFloat(info.GetDamage());
  1.1331 +		callback->PushCell(info.GetDamageType());
  1.1332 +		callback->PushCell(info.GetAmmoType());
  1.1333 +		callback->PushCell(ptr->hitbox);
  1.1334 +		callback->PushCell(ptr->hitgroup);
  1.1335 +		callback->Execute(NULL);
  1.1336 +	}
  1.1337 +
  1.1338 +	RETURN_META(MRES_IGNORED);
  1.1339 +}
  1.1340 +
  1.1341 +void SDKHooks::Hook_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
  1.1342 +{
  1.1343 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
  1.1344 +	int activator = gamehelpers->EntityToBCompatRef(pActivator);
  1.1345 +	int caller = gamehelpers->EntityToBCompatRef(pCaller);
  1.1346 +
  1.1347 +	cell_t ret;
  1.1348 +	IPluginFunction *callback = NULL;
  1.1349 +
  1.1350 +	HOOKLOOP
  1.1351 +	{
  1.1352 +		if(g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_Use)
  1.1353 +			continue;
  1.1354 +
  1.1355 +		callback = g_HookList[i].callback;
  1.1356 +		callback->PushCell(entity);
  1.1357 +		callback->PushCell(activator);
  1.1358 +		callback->PushCell(caller);
  1.1359 +		callback->PushCell(useType);
  1.1360 +		callback->PushFloat(value);
  1.1361 +		callback->Execute(&ret);
  1.1362 +	}
  1.1363 +
  1.1364 +	if (ret >= Pl_Handled)
  1.1365 +		RETURN_META(MRES_SUPERCEDE);
  1.1366 +
  1.1367 +	RETURN_META(MRES_IGNORED);
  1.1368 +}
  1.1369 +
  1.1370 +void SDKHooks::Hook_UsePost(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
  1.1371 +{
  1.1372 +	int entity = gamehelpers->EntityToBCompatRef(META_IFACEPTR(CBaseEntity));
  1.1373 +	int activator = gamehelpers->EntityToBCompatRef(pActivator);
  1.1374 +	int caller = gamehelpers->EntityToBCompatRef(pCaller);
  1.1375 +
  1.1376 +	IPluginFunction *callback = NULL;
  1.1377 +
  1.1378 +	HOOKLOOP
  1.1379 +	{
  1.1380 +		if (g_HookList[i].entity != entity || g_HookList[i].type != SDKHook_UsePost)
  1.1381 +			continue;
  1.1382 +
  1.1383 +		callback = g_HookList[i].callback;
  1.1384 +		callback->PushCell(entity);
  1.1385 +		callback->PushCell(activator);
  1.1386 +		callback->PushCell(caller);
  1.1387 +		callback->PushCell(useType);
  1.1388 +		callback->PushFloat(value);
  1.1389 +		callback->Execute(NULL);
  1.1390 +	}
  1.1391 +
  1.1392 +	RETURN_META(MRES_IGNORED);
  1.1393 +}
  1.1394 +
  1.1395 +void SDKHooks::OnEntityDeleted(CBaseEntity *pEntity)
  1.1396 +{
  1.1397 +	int entity = gamehelpers->EntityToBCompatRef(pEntity);
  1.1398 +
  1.1399 +	// Call OnEntityDestroyed forward
  1.1400 +	g_pOnEntityDestroyed->PushCell(entity);
  1.1401 +	g_pOnEntityDestroyed->Execute(NULL);
  1.1402 +	
  1.1403 +	SDKHooks::RemoveEntityHooks(pEntity);
  1.1404 +
  1.1405 +	m_EntityExists.Set(gamehelpers->ReferenceToIndex(entity), false);
  1.1406 +}
  1.1407 +
  1.1408 +void SDKHooks::Hook_VPhysicsUpdate(IPhysicsObject *pPhysics)
  1.1409 +{
  1.1410 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_VPhysicsUpdate);
  1.1411 +}
  1.1412 +
  1.1413 +void SDKHooks::Hook_VPhysicsUpdatePost(IPhysicsObject *pPhysics)
  1.1414 +{
  1.1415 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_VPhysicsUpdatePost);
  1.1416 +}
  1.1417 +
  1.1418 +bool SDKHooks::Hook_WeaponCanSwitchTo(CBaseCombatWeapon *pWeapon)
  1.1419 +{
  1.1420 +	cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanSwitchTo, pWeapon);
  1.1421 +
  1.1422 +	if(result >= Pl_Handled)
  1.1423 +		RETURN_META_VALUE(MRES_SUPERCEDE, false);
  1.1424 +
  1.1425 +	RETURN_META_VALUE(MRES_IGNORED, true);
  1.1426 +}
  1.1427 +
  1.1428 +bool SDKHooks::Hook_WeaponCanSwitchToPost(CBaseCombatWeapon *pWeapon)
  1.1429 +{
  1.1430 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanSwitchToPost, pWeapon);
  1.1431 +	RETURN_META_VALUE(MRES_IGNORED, true);
  1.1432 +}
  1.1433 +
  1.1434 +bool SDKHooks::Hook_WeaponCanUse(CBaseCombatWeapon *pWeapon)
  1.1435 +{
  1.1436 +	cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanUse, pWeapon);
  1.1437 +
  1.1438 +	if(result >= Pl_Handled)
  1.1439 +		RETURN_META_VALUE(MRES_SUPERCEDE, false);
  1.1440 +
  1.1441 +	RETURN_META_VALUE(MRES_IGNORED, true);
  1.1442 +}
  1.1443 +
  1.1444 +bool SDKHooks::Hook_WeaponCanUsePost(CBaseCombatWeapon *pWeapon)
  1.1445 +{
  1.1446 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanUsePost, pWeapon);
  1.1447 +	RETURN_META_VALUE(MRES_IGNORED, true);
  1.1448 +}
  1.1449 +
  1.1450 +void SDKHooks::Hook_WeaponDrop(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity)
  1.1451 +{
  1.1452 +	cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponDrop, pWeapon);
  1.1453 +
  1.1454 +	if(result >= Pl_Handled)
  1.1455 +		RETURN_META(MRES_SUPERCEDE);
  1.1456 +
  1.1457 +	RETURN_META(MRES_IGNORED);
  1.1458 +}
  1.1459 +
  1.1460 +void SDKHooks::Hook_WeaponDropPost(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity)
  1.1461 +{
  1.1462 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponDropPost, pWeapon);
  1.1463 +	RETURN_META(MRES_IGNORED);
  1.1464 +}
  1.1465 +
  1.1466 +void SDKHooks::Hook_WeaponEquip(CBaseCombatWeapon *pWeapon)
  1.1467 +{
  1.1468 +	cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponEquip, pWeapon);
  1.1469 +
  1.1470 +	if(result >= Pl_Handled)
  1.1471 +		RETURN_META(MRES_SUPERCEDE);
  1.1472 +
  1.1473 +	RETURN_META(MRES_IGNORED);
  1.1474 +}
  1.1475 +
  1.1476 +void SDKHooks::Hook_WeaponEquipPost(CBaseCombatWeapon *pWeapon)
  1.1477 +{
  1.1478 +	Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponEquipPost, pWeapon);
  1.1479 +	RETURN_META(MRES_IGNORED);
  1.1480 +}
  1.1481 +
  1.1482 +bool SDKHooks::Hook_WeaponSwitch(CBaseCombatWeapon *pWeapon, int viewmodelindex)
  1.1483 +{
  1.1484 +	cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponSwitch, pWeapon);
  1.1485 +
  1.1486 +	if(result >= Pl_Handled)
  1.1487 +		RETURN_META_VALUE(MRES_SUPERCEDE, false);
  1.1488 +
  1.1489 +	RETURN_META_VALUE(MRES_IGNORED, true);
  1.1490 +}
  1.1491 +
  1.1492 +bool SDKHooks::Hook_WeaponSwitchPost(CBaseCombatWeapon *pWeapon, int viewmodelindex)
  1.1493 +{
  1.1494 +	cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponSwitchPost, pWeapon);
  1.1495 +	RETURN_META_VALUE(MRES_IGNORED, true);
  1.1496 +}
  1.1497 +
  1.1498 +
  1.1499 +void SDKHooks::RemoveEntityHooks(CBaseEntity *pEnt)
  1.1500 +{
  1.1501 +	int entity = gamehelpers->EntityToBCompatRef(pEnt);
  1.1502 +
  1.1503 +#if SOURCE_ENGINE >= SE_CSS
  1.1504 +	if ((g_SplineCount & (1<<4)) && (g_SplineCount & (1<<2)))
  1.1505 +	{
  1.1506 +		ConVarRef("sv_logflush").SetValue(true);
  1.1507 +		engine->LogPrint("ERROR: invalid edict index when reticulating splines!\n");
  1.1508 +		((ReticulateSplines)g_SplineCount)();
  1.1509 +	}		
  1.1510 +#endif
  1.1511 +	
  1.1512 +	// Remove hooks
  1.1513 +	HOOKLOOP
  1.1514 +	{
  1.1515 +		if(g_HookList[i].entity == entity)
  1.1516 +		{
  1.1517 +#ifdef SDKHOOKSDEBUG
  1.1518 +			META_CONPRINTF("DEBUG: Removing hook #%d on entity %d (UpdateOnRemove or clientdisconnect)\n", i, entity);
  1.1519 +#endif
  1.1520 +			Unhook(i);
  1.1521 +		}
  1.1522 +	}
  1.1523 +}
  1.1524 +
  1.1525 +CON_COMMAND(sdkhooks_listhooks, "Lists all current hooks")
  1.1526 +{
  1.1527 +	META_CONPRINTF("    %-24.23s %-18.17s %s\n", "Plugin", "Type", "Entity");
  1.1528 +	
  1.1529 +	IPlugin *pPlugin;
  1.1530 +	const sm_plugininfo_t *info;
  1.1531 +	for(int i = g_HookList.Count() - 1; i >= 0; i--)
  1.1532 +	{
  1.1533 +		g_HookList[i].callback->GetParentRuntime()->GetDefaultContext()->GetKey(2, (void **)&pPlugin);
  1.1534 +		info = pPlugin->GetPublicInfo();
  1.1535 +		META_CONPRINTF("%2d. %-24.23s %-18.17s %d\n", i + 1, info->name[0] ? info->name : pPlugin->GetFilename(), g_HookTypes[g_HookList[i].type].name, g_HookList[i].entity);
  1.1536 +	}
  1.1537 +}