Clean up TF2 ext CalcCritical code (bug 5894, r=voided).
authorNicholas Hastings <skamonkey@gmail.com>
Thu Aug 29 09:27:35 2013 -0400 (2013-08-29)
changeset 4092f184c016f489
parent 4091 7d4cd212595b
child 4093 da128cd7be77
Clean up TF2 ext CalcCritical code (bug 5894, r=voided).
extensions/tf2/criticals.cpp
extensions/tf2/criticals.h
extensions/tf2/extension.cpp
extensions/tf2/util.cpp
extensions/tf2/util.h
gamedata/sm-tf2.games.txt
     1.1 --- a/extensions/tf2/criticals.cpp	Wed Aug 28 13:46:34 2013 -0400
     1.2 +++ b/extensions/tf2/criticals.cpp	Thu Aug 29 09:27:35 2013 -0400
     1.3 @@ -32,330 +32,169 @@
     1.4  #include "criticals.h"
     1.5  #include "util.h"
     1.6  
     1.7 -IServerGameEnts *gameents = NULL;
     1.8 +CritManager g_CritManager;
     1.9 +
    1.10 +IForward *g_critForward = nullptr;
    1.11 +
    1.12 +SH_DECL_MANUALHOOK0(CalcIsAttackCriticalHelper, 0, 0, 0, bool);
    1.13 +SH_DECL_MANUALHOOK0(CalcIsAttackCriticalHelperNoCrits, 0, 0, 0, bool);
    1.14 +
    1.15 +const char TF_WEAPON_DATATABLE[] = "DT_TFWeaponBase";
    1.16  
    1.17 -CDetour *calcIsAttackCriticalDetour = NULL;
    1.18 -CDetour *calcIsAttackCriticalMeleeDetour = NULL;
    1.19 -CDetour *calcIsAttackCriticalBowDetour = NULL;
    1.20 -CDetour *calcIsAttackCriticalKnifeDetour = NULL;
    1.21 -CDetour *calcIsAttackCriticalNoCritsDetour = NULL;
    1.22 -CDetour *calcIsAttackCriticalNoCritsMeleeDetour = NULL;
    1.23 +CritManager::CritManager() :
    1.24 +	m_enabled(false),
    1.25 +	m_hooksSetup(false)
    1.26 +{
    1.27 +	m_entsHooked.Init();
    1.28 +}
    1.29  
    1.30 -int nextMeleeCritOffset = -1;
    1.31 +bool CritManager::TryEnable()
    1.32 +{
    1.33 +	if (!m_hooksSetup)
    1.34 +	{
    1.35 +		int offset;
    1.36  
    1.37 -IForward *g_critForward = NULL;
    1.38 +		if (!g_pGameConf->GetOffset("CalcIsAttackCriticalHelper", &offset))
    1.39 +		{
    1.40 +			g_pSM->LogError(myself, "Failed to find CalcIsAttackCriticalHelper offset");
    1.41 +			return false;
    1.42 +		}
    1.43 +
    1.44 +		SH_MANUALHOOK_RECONFIGURE(CalcIsAttackCriticalHelper, offset, 0, 0);
    1.45  
    1.46 -enum DetourResult
    1.47 -{
    1.48 -	Result_Ignore,
    1.49 -	Result_NoCrit,
    1.50 -	Result_Crit,
    1.51 -};
    1.52 +		if (!g_pGameConf->GetOffset("CalcIsAttackCriticalHelperNoCrits", &offset))
    1.53 +		{
    1.54 +			g_pSM->LogError(myself, "Failed to find CalcIsAttackCriticalHelperNoCrits offset");
    1.55 +			return false;
    1.56 +		}
    1.57 +
    1.58 +		SH_MANUALHOOK_RECONFIGURE(CalcIsAttackCriticalHelperNoCrits, offset, 0, 0);
    1.59 +
    1.60 +		m_hooksSetup = true;
    1.61 +	}
    1.62  
    1.63 -int CheckBaseHandle(CBaseHandle &hndl)
    1.64 -{
    1.65 -	if (!hndl.IsValid())
    1.66 +	for (size_t i = playerhelpers->GetMaxClients() + 1; i < MAX_EDICTS; ++i)
    1.67  	{
    1.68 -		return -1;
    1.69 +		CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i);
    1.70 +		if (pEntity == nullptr)
    1.71 +			continue;
    1.72 +
    1.73 +		IServerUnknown *pUnknown = (IServerUnknown *)pEntity;
    1.74 +		IServerNetworkable *pNetworkable = pUnknown->GetNetworkable();
    1.75 +		if (!pNetworkable)
    1.76 +			continue;
    1.77 +
    1.78 +		if (!UTIL_ContainsDataTable(pNetworkable->GetServerClass()->m_pTable, TF_WEAPON_DATATABLE))
    1.79 +			continue;
    1.80 +
    1.81 +		SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelper, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false);
    1.82 +		SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelperNoCrits, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false);
    1.83 +
    1.84 +		m_entsHooked.Set(i);
    1.85  	}
    1.86  
    1.87 -	int index = hndl.GetEntryIndex();
    1.88 +	m_enabled = true;
    1.89  
    1.90 -	edict_t *pStoredEdict;
    1.91 +	return true;
    1.92 +}
    1.93  
    1.94 -	pStoredEdict = engine->PEntityOfEntIndex(index);
    1.95 +void CritManager::Disable()
    1.96 +{
    1.97 +	int i = m_entsHooked.FindNextSetBit(playerhelpers->GetMaxClients() + 1);
    1.98 +	for (i; i != -1; i = m_entsHooked.FindNextSetBit(i))
    1.99 +	{
   1.100 +		CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i);
   1.101 +		SH_REMOVE_MANUALHOOK(CalcIsAttackCriticalHelper, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false);
   1.102 +		SH_REMOVE_MANUALHOOK(CalcIsAttackCriticalHelperNoCrits, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false);
   1.103  
   1.104 -	if (pStoredEdict == NULL)
   1.105 -	{
   1.106 -		return -1;
   1.107 +		m_entsHooked.Set(i, false);
   1.108  	}
   1.109  
   1.110 -	IServerEntity *pSE = pStoredEdict->GetIServerEntity();
   1.111 +	m_enabled = false;
   1.112 +}
   1.113  
   1.114 -	if (pSE == NULL)
   1.115 -	{
   1.116 -		return -1;
   1.117 -	}
   1.118 +void CritManager::OnEntityCreated(CBaseEntity *pEntity, const char *classname)
   1.119 +{
   1.120 +	if (!m_enabled)
   1.121 +		return;
   1.122  
   1.123 -	if (pSE->GetRefEHandle() != hndl)
   1.124 -	{
   1.125 -		return -1;
   1.126 -	}
   1.127 +	IServerUnknown *pUnknown = (IServerUnknown *)pEntity;
   1.128 +	IServerNetworkable *pNetworkable = pUnknown->GetNetworkable();
   1.129 +	if (!pNetworkable)
   1.130 +		return;
   1.131  
   1.132 -	return index;
   1.133 +	if (!UTIL_ContainsDataTable(pNetworkable->GetServerClass()->m_pTable, TF_WEAPON_DATATABLE))
   1.134 +		return;
   1.135 +
   1.136 +	SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelper, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false);
   1.137 +	SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelperNoCrits, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false);
   1.138 +
   1.139 +	m_entsHooked.Set(gamehelpers->EntityToBCompatRef(pEntity));
   1.140  }
   1.141  
   1.142 -DetourResult DetourCallback(CBaseEntity *pEnt, bool bMeleeNoCrits)
   1.143 +void CritManager::OnEntityDestroyed(CBaseEntity *pEntity)
   1.144  {
   1.145 -	edict_t *pEdict = gameents->BaseEntityToEdict((CBaseEntity *)pEnt);
   1.146 +	if (!m_enabled)
   1.147 +		return;
   1.148 +
   1.149 +	int index = gamehelpers->EntityToBCompatRef(pEntity);
   1.150 +	if (index < 0 || index >= MAX_EDICTS)
   1.151 +		return;
   1.152 +	
   1.153 +	if (!m_entsHooked.IsBitSet(index))
   1.154 +		return;
   1.155 +
   1.156 +	SH_REMOVE_MANUALHOOK(CalcIsAttackCriticalHelper, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false);
   1.157 +	SH_REMOVE_MANUALHOOK(CalcIsAttackCriticalHelperNoCrits, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelpers), false);
   1.158  
   1.159 -	if (!pEdict)
   1.160 +	m_entsHooked.Set(index, false);
   1.161 +}
   1.162 +
   1.163 +bool CritManager::Hook_CalcIsAttackCriticalHelpers()
   1.164 +{
   1.165 +	CBaseEntity *pWeapon = META_IFACEPTR(CBaseEntity);
   1.166 +	
   1.167 +	// If there's an invalid ent or invalid networkable here, we've got issues elsewhere.
   1.168 +
   1.169 +	IServerNetworkable *pNetWeapon = ((IServerUnknown *)pWeapon)->GetNetworkable();
   1.170 +	ServerClass *pServerClass = pNetWeapon->GetServerClass();
   1.171 +	if (!pServerClass)
   1.172  	{
   1.173 -		g_pSM->LogMessage(myself, "Entity Error");
   1.174 -		return Result_Ignore;
   1.175 +		g_pSM->LogError(myself, "Invalid server class on weapon.");
   1.176 +		RETURN_META_VALUE(MRES_IGNORED, false);
   1.177  	}
   1.178  
   1.179  	sm_sendprop_info_t info;
   1.180 -
   1.181 -	if (!gamehelpers->FindSendPropInfo(pEdict->GetNetworkable()->GetServerClass()->GetName(), "m_hOwnerEntity", &info))
   1.182 +	if (!gamehelpers->FindSendPropInfo(pServerClass->GetName(), "m_hOwnerEntity", &info))
   1.183  	{
   1.184 -		g_pSM->LogMessage(myself, "Offset Error");
   1.185 -		return Result_Ignore;
   1.186 -	}
   1.187 -
   1.188 -	if (!g_critForward)
   1.189 -	{
   1.190 -		g_pSM->LogMessage(myself, "Invalid Forward");
   1.191 -		return Result_Ignore;
   1.192 +		g_pSM->LogError(myself, "Could not find m_hOwnerEntity on %s", pServerClass->GetName());
   1.193 +		RETURN_META_VALUE(MRES_IGNORED, false);
   1.194  	}
   1.195  
   1.196 -	int returnValue=0;
   1.197 -
   1.198 -	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEnt + info.actual_offset);
   1.199 -	int index = CheckBaseHandle(hndl);
   1.200 +	int returnValue = 0;
   1.201  
   1.202 -	//Skip CTFWeaponBaseMelee::CalcIsAttackCriticalHelperNoCrits if m_iNextMeleeCrit is not 2
   1.203 -	if (bMeleeNoCrits)
   1.204 +	int ownerIndex = -1;
   1.205 +	CBaseHandle &hndl = *(CBaseHandle *) ((intptr_t)pWeapon + info.actual_offset);
   1.206 +	CBaseEntity *pHandleEntity = gamehelpers->ReferenceToEntity(hndl.GetEntryIndex());
   1.207 +
   1.208 +	if (pHandleEntity != nullptr && hndl == reinterpret_cast<IHandleEntity *>(pHandleEntity)->GetRefEHandle())
   1.209  	{
   1.210 -		CBaseEntity *pPlayer = UTIL_GetCBaseEntity(index, true);
   1.211 -		if (pPlayer && *(uint32_t *)((intptr_t)pPlayer + nextMeleeCritOffset) != 2)
   1.212 -			return Result_Ignore;
   1.213 +		ownerIndex = hndl.GetEntryIndex();
   1.214  	}
   1.215  
   1.216 -	g_critForward->PushCell(index); //Client index
   1.217 -	g_critForward->PushCell(engine->IndexOfEdict(pEdict)); // Weapon index
   1.218 -	g_critForward->PushString(pEdict->GetClassName()); //Weapon classname
   1.219 +	g_critForward->PushCell(ownerIndex); //Client index
   1.220 +	g_critForward->PushCell(gamehelpers->EntityToBCompatRef(pWeapon)); // Weapon index
   1.221 +	g_critForward->PushString(gamehelpers->GetEntityClassname(pWeapon)); //Weapon classname
   1.222  	g_critForward->PushCellByRef(&returnValue); //return value
   1.223  
   1.224  	cell_t result = 0;
   1.225  
   1.226  	g_critForward->Execute(&result);
   1.227  
   1.228 -	if (result)
   1.229 -	{
   1.230 -		if (returnValue)
   1.231 -		{
   1.232 -			return Result_Crit;
   1.233 -		}
   1.234 -		else
   1.235 -		{
   1.236 -			return Result_NoCrit;
   1.237 -		}
   1.238 -	}
   1.239 -	else
   1.240 -	{
   1.241 -		return Result_Ignore;
   1.242 -	}
   1.243 -}
   1.244 -
   1.245 -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelperMelee, bool)
   1.246 -{
   1.247 -	DetourResult result = DetourCallback((CBaseEntity *)this, false);
   1.248 -
   1.249 -	if (result == Result_Ignore)
   1.250 -	{
   1.251 -		return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelperMelee)();
   1.252 -	}
   1.253 -	else if (result == Result_NoCrit)
   1.254 -	{
   1.255 -		return 0;
   1.256 -	}
   1.257 -	else
   1.258 -	{
   1.259 -		return 1;
   1.260 -	}
   1.261 -}
   1.262 -
   1.263 -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelper, bool)
   1.264 -{
   1.265 -	DetourResult result = DetourCallback((CBaseEntity *)this, false);
   1.266 -
   1.267 -	if (result == Result_Ignore)
   1.268 -	{
   1.269 -		return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelper)();
   1.270 -	}
   1.271 -	else if (result == Result_NoCrit)
   1.272 -	{
   1.273 -		return 0;
   1.274 -	}
   1.275 -	else
   1.276 -	{
   1.277 -		return 1;
   1.278 -	}
   1.279 -}
   1.280 -
   1.281 -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelperBow, bool)
   1.282 -{
   1.283 -	DetourResult result = DetourCallback((CBaseEntity *)this, false);
   1.284 -
   1.285 -	if (result == Result_Ignore)
   1.286 -	{
   1.287 -		return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelperBow)();
   1.288 -	}
   1.289 -	else if (result == Result_NoCrit)
   1.290 -	{
   1.291 -		return 0;
   1.292 -	}
   1.293 -	else
   1.294 -	{
   1.295 -		return 1;
   1.296 -	}
   1.297 -}
   1.298 -
   1.299 -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelperKnife, bool)
   1.300 -{
   1.301 -	DetourResult result = DetourCallback((CBaseEntity *)this, false);
   1.302 -
   1.303 -	if (result == Result_Ignore)
   1.304 -	{
   1.305 -		return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelperKnife)();
   1.306 -	}
   1.307 -	else if (result == Result_NoCrit)
   1.308 -	{
   1.309 -		return 0;
   1.310 -	}
   1.311 -	else
   1.312 -	{
   1.313 -		return 1;
   1.314 -	}
   1.315 -}
   1.316 -
   1.317 -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelperNoCrits, bool)
   1.318 -{
   1.319 -	DetourResult result = DetourCallback((CBaseEntity *)this, false);
   1.320 -
   1.321 -	if (result == Result_Ignore)
   1.322 -	{
   1.323 -		return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelperNoCrits)();
   1.324 -	}
   1.325 -	else if (result == Result_NoCrit)
   1.326 -	{
   1.327 -		return 0;
   1.328 -	}
   1.329 -	else
   1.330 +	if (result && returnValue)
   1.331  	{
   1.332 -		return 1;
   1.333 -	}
   1.334 -}
   1.335 -
   1.336 -DETOUR_DECL_MEMBER0(CalcIsAttackCriticalHelperNoCritsMelee, bool)
   1.337 -{
   1.338 -	DetourResult result = DetourCallback((CBaseEntity *)this, true);
   1.339 -
   1.340 -	if (result == Result_Ignore)
   1.341 -	{
   1.342 -		return DETOUR_MEMBER_CALL(CalcIsAttackCriticalHelperNoCritsMelee)();
   1.343 -	}
   1.344 -	else if (result == Result_NoCrit)
   1.345 -	{
   1.346 -		return 0;
   1.347 -	}
   1.348 -	else
   1.349 -	{
   1.350 -		return 1;
   1.351 -	}
   1.352 -}
   1.353 -
   1.354 -bool InitialiseCritDetours()
   1.355 -{
   1.356 -	sm_sendprop_info_t prop;
   1.357 -
   1.358 -	calcIsAttackCriticalDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelper, "CalcCritical");
   1.359 -	calcIsAttackCriticalMeleeDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelperMelee, "CalcCriticalMelee");
   1.360 -	calcIsAttackCriticalBowDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelperBow, "CalcCriticalBow");
   1.361 -	calcIsAttackCriticalKnifeDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelperKnife, "CalcCriticalKnife");
   1.362 -	calcIsAttackCriticalNoCritsDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelperNoCrits, "CalcCriticalNoCrits");
   1.363 -	calcIsAttackCriticalNoCritsMeleeDetour = DETOUR_CREATE_MEMBER(CalcIsAttackCriticalHelperNoCritsMelee, "CalcCriticalNoCritsMelee");
   1.364 -
   1.365 -	bool HookCreated = false;
   1.366 -
   1.367 -	if (calcIsAttackCriticalDetour != NULL)
   1.368 -	{
   1.369 -		calcIsAttackCriticalDetour->EnableDetour();
   1.370 -		HookCreated = true;
   1.371 -	}
   1.372 -
   1.373 -	if (calcIsAttackCriticalMeleeDetour != NULL)
   1.374 -	{
   1.375 -		calcIsAttackCriticalMeleeDetour->EnableDetour();
   1.376 -		HookCreated = true;
   1.377 -	}
   1.378 -
   1.379 -	if (calcIsAttackCriticalBowDetour != NULL)
   1.380 -	{
   1.381 -		calcIsAttackCriticalBowDetour->EnableDetour();
   1.382 -		HookCreated = true;
   1.383 -	}
   1.384 -
   1.385 -	if (calcIsAttackCriticalKnifeDetour != NULL)
   1.386 -	{
   1.387 -		calcIsAttackCriticalKnifeDetour->EnableDetour();
   1.388 -		HookCreated = true;
   1.389 -	}
   1.390 -
   1.391 -	if (calcIsAttackCriticalNoCritsDetour != NULL)
   1.392 -	{
   1.393 -		calcIsAttackCriticalNoCritsDetour->EnableDetour();
   1.394 -		HookCreated = true;
   1.395 -	}
   1.396 -
   1.397 -	if (calcIsAttackCriticalNoCritsMeleeDetour != NULL)
   1.398 -	{
   1.399 -		calcIsAttackCriticalNoCritsMeleeDetour->EnableDetour();
   1.400 -		if (!gamehelpers->FindSendPropInfo("CTFPlayer", "m_iNextMeleeCrit", &prop))
   1.401 -		{
   1.402 -			g_pSM->LogError(myself, "Failed to find m_iNextMeleeCrit prop offset");
   1.403 -			return false;
   1.404 -		}
   1.405 -		nextMeleeCritOffset = prop.actual_offset;
   1.406 -		HookCreated = true;
   1.407 -	}
   1.408 -
   1.409 -	if (HookCreated)
   1.410 -	{
   1.411 -		return true;
   1.412 -	}
   1.413 -
   1.414 -	g_pSM->LogError(myself, "No critical hit forwards could be initialized - Disabled critical hit hooks");
   1.415 -
   1.416 -	return false;
   1.417 -}
   1.418 -
   1.419 -void RemoveCritDetours()
   1.420 -{
   1.421 -	if (calcIsAttackCriticalDetour != NULL)
   1.422 -	{
   1.423 -		calcIsAttackCriticalDetour->Destroy();
   1.424 -		calcIsAttackCriticalDetour = NULL;
   1.425 -	}
   1.426 -
   1.427 -	if (calcIsAttackCriticalMeleeDetour != NULL)
   1.428 -	{
   1.429 -		calcIsAttackCriticalMeleeDetour->Destroy();
   1.430 -		calcIsAttackCriticalMeleeDetour = NULL;
   1.431 -	}
   1.432 -
   1.433 -	if (calcIsAttackCriticalBowDetour != NULL)
   1.434 -	{
   1.435 -		calcIsAttackCriticalBowDetour->Destroy();
   1.436 -		calcIsAttackCriticalBowDetour = NULL;
   1.437 +		RETURN_META_VALUE(MRES_SUPERCEDE, true);
   1.438  	}
   1.439  	
   1.440 -	if (calcIsAttackCriticalKnifeDetour != NULL)
   1.441 -	{
   1.442 -		calcIsAttackCriticalKnifeDetour->Destroy();
   1.443 -		calcIsAttackCriticalKnifeDetour = NULL;
   1.444 -	}
   1.445 -
   1.446 -	if (calcIsAttackCriticalNoCritsDetour != NULL)
   1.447 -	{
   1.448 -		calcIsAttackCriticalNoCritsDetour->Destroy();
   1.449 -		calcIsAttackCriticalNoCritsDetour = NULL;
   1.450 -	}
   1.451 -
   1.452 -	if (calcIsAttackCriticalNoCritsMeleeDetour != NULL)
   1.453 -	{
   1.454 -		calcIsAttackCriticalNoCritsMeleeDetour->Destroy();
   1.455 -		calcIsAttackCriticalNoCritsMeleeDetour = NULL;
   1.456 -	}
   1.457 +	RETURN_META_VALUE(MRES_IGNORED, false);
   1.458  }
     2.1 --- a/extensions/tf2/criticals.h	Wed Aug 28 13:46:34 2013 -0400
     2.2 +++ b/extensions/tf2/criticals.h	Thu Aug 29 09:27:35 2013 -0400
     2.3 @@ -36,12 +36,38 @@
     2.4  #include <jit/jit_helpers.h>
     2.5  #include <jit/x86/x86_macros.h>
     2.6  #include "CDetour/detours.h"
     2.7 +#include "ISDKHooks.h"
     2.8  
     2.9 -bool InitialiseCritDetours();
    2.10 -void RemoveCritDetours();
    2.11 +class CritManager : public ISMEntityListener
    2.12 +{
    2.13 +public:
    2.14 +	CritManager();
    2.15 +
    2.16 +public:
    2.17 +	bool TryEnable();
    2.18 +	void Disable();
    2.19 +
    2.20 +	// ISMEntityListener
    2.21 +public:
    2.22 +	virtual void OnEntityCreated(CBaseEntity *pEntity, const char *classname);
    2.23 +	virtual void OnEntityDestroyed(CBaseEntity *pEntity);
    2.24 +
    2.25 +private:
    2.26 +	void HookEntityIfWeapon(CBaseEntity *pEntity);
    2.27 +	void UnhookEntityIfHooked(CBaseEntity *pEntity);
    2.28 +
    2.29 +public:
    2.30 +	// CritHook
    2.31 +	bool Hook_CalcIsAttackCriticalHelpers();
    2.32 +
    2.33 +private:
    2.34 +	bool m_enabled;
    2.35 +	bool m_hooksSetup;
    2.36 +	CBitVec<MAX_EDICTS> m_entsHooked;	
    2.37 +};
    2.38 +
    2.39 +extern CritManager g_CritManager;
    2.40  
    2.41  extern IForward *g_critForward;
    2.42  
    2.43 -extern IServerGameEnts *gameents;
    2.44 -
    2.45  #endif //_INCLUDE_SOURCEMOD_CRITICALS_H_
     3.1 --- a/extensions/tf2/extension.cpp	Wed Aug 28 13:46:34 2013 -0400
     3.2 +++ b/extensions/tf2/extension.cpp	Thu Aug 29 09:27:35 2013 -0400
     3.3 @@ -41,6 +41,7 @@
     3.4  #include "gameplayrules.h"
     3.5  #include "teleporter.h"
     3.6  #include "CDetour/detours.h"
     3.7 +#include "ISDKHooks.h"
     3.8  
     3.9  /**
    3.10   * @file extension.cpp
    3.11 @@ -52,6 +53,7 @@
    3.12  IGameConfig *g_pGameConf = NULL;
    3.13  
    3.14  IBinTools *g_pBinTools = NULL;
    3.15 +ISDKHooks *g_pSDKHooks = NULL;
    3.16  
    3.17  SMEXT_LINK(&g_TF2Tools);
    3.18  
    3.19 @@ -91,6 +93,7 @@
    3.20  	}
    3.21  
    3.22  	sharesys->AddDependency(myself, "bintools.ext", true, true);
    3.23 +	sharesys->AddDependency(myself, "sdkhooks.ext", true, true);
    3.24  
    3.25  	char conf_error[255] = "";
    3.26  	if (!gameconfs->LoadGameConfigFile("sm-tf2.games", &g_pGameConf, conf_error, sizeof(conf_error)))
    3.27 @@ -151,8 +154,6 @@
    3.28  
    3.29  	GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
    3.30  
    3.31 -	GET_V_IFACE_CURRENT(GetServerFactory, gameents, IServerGameEnts, INTERFACEVERSION_SERVERGAMEENTS);
    3.32 -
    3.33  	GET_V_IFACE_CURRENT(GetEngineFactory, m_GameEventManager, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2);
    3.34  	m_GameEventManager->AddListener(this, "teamplay_restart_round", true);
    3.35  
    3.36 @@ -177,11 +178,22 @@
    3.37  	forwards->ReleaseForward(g_waitingPlayersStartForward);
    3.38  	forwards->ReleaseForward(g_waitingPlayersEndForward);
    3.39  	forwards->ReleaseForward(g_teleportForward);
    3.40 +
    3.41 +	if (g_pSDKHooks != nullptr)
    3.42 +	{
    3.43 +		g_pSDKHooks->RemoveEntityListener(&g_CritManager);
    3.44 +	}
    3.45  }
    3.46  
    3.47  void TF2Tools::SDK_OnAllLoaded()
    3.48  {
    3.49  	SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
    3.50 +	SM_GET_LATE_IFACE(SDKHOOKS, g_pSDKHooks);
    3.51 +
    3.52 +	if (g_pSDKHooks != nullptr)
    3.53 +	{
    3.54 +		g_pSDKHooks->AddEntityListener(&g_CritManager);
    3.55 +	}
    3.56  }
    3.57  
    3.58  bool TF2Tools::RegisterConCommandBase(ConCommandBase *pVar)
    3.59 @@ -198,6 +210,7 @@
    3.60  bool TF2Tools::QueryRunning(char *error, size_t maxlength)
    3.61  {
    3.62  	SM_CHECK_IFACE(BINTOOLS, g_pBinTools);
    3.63 +	SM_GET_LATE_IFACE(SDKHOOKS, g_pSDKHooks);
    3.64  
    3.65  	return true;
    3.66  }
    3.67 @@ -209,6 +222,11 @@
    3.68  		return false;
    3.69  	}
    3.70  
    3.71 +	if (pInterface == g_pSDKHooks)
    3.72 +	{
    3.73 +		return false;
    3.74 +	}
    3.75 +
    3.76  	return IExtensionInterface::QueryInterfaceDrop(pInterface);
    3.77  }
    3.78  
    3.79 @@ -321,7 +339,7 @@
    3.80  {
    3.81  	if (!m_CritDetoursEnabled && g_critForward->GetFunctionCount())
    3.82  	{
    3.83 -		m_CritDetoursEnabled = InitialiseCritDetours();
    3.84 +		m_CritDetoursEnabled = g_CritManager.TryEnable();
    3.85  	}
    3.86  
    3.87  	if (!m_IsHolidayDetourEnabled && g_isHolidayForward->GetFunctionCount())
    3.88 @@ -353,7 +371,7 @@
    3.89  {
    3.90  	if (m_CritDetoursEnabled && !g_critForward->GetFunctionCount())
    3.91  	{
    3.92 -		RemoveCritDetours();
    3.93 +		g_CritManager.Disable();
    3.94  		m_CritDetoursEnabled = false;
    3.95  	}
    3.96  	if (m_IsHolidayDetourEnabled && !g_isHolidayForward->GetFunctionCount())
     4.1 --- a/extensions/tf2/util.cpp	Wed Aug 28 13:46:34 2013 -0400
     4.2 +++ b/extensions/tf2/util.cpp	Thu Aug 29 09:27:35 2013 -0400
     4.3 @@ -88,6 +88,38 @@
     4.4  	return false;
     4.5  }
     4.6  
     4.7 +bool UTIL_ContainsDataTable(SendTable *pTable, const char *name)
     4.8 +{
     4.9 +	const char *pname = pTable->GetName();
    4.10 +	int props = pTable->GetNumProps();
    4.11 +	SendProp *prop;
    4.12 +	SendTable *table;
    4.13 +
    4.14 +	if (pname && strcmp(name, pname) == 0)
    4.15 +		return true;
    4.16 +
    4.17 +	for (int i = 0; i < props; i++)
    4.18 +	{
    4.19 +		prop = pTable->GetProp(i);
    4.20 +
    4.21 +		if ((table = prop->GetDataTable()) != NULL)
    4.22 +		{
    4.23 +			pname = table->GetName();
    4.24 +			if (pname && strcmp(name, pname) == 0)
    4.25 +			{
    4.26 +				return true;
    4.27 +			}
    4.28 +
    4.29 +			if (UTIL_ContainsDataTable(table, name))
    4.30 +			{
    4.31 +				return true;
    4.32 +			}
    4.33 +		}
    4.34 +	}
    4.35 +
    4.36 +	return false;
    4.37 +}
    4.38 +
    4.39  ServerClass *UTIL_FindServerClass(const char *classname)
    4.40  {
    4.41  	ServerClass *sc = gamedll->GetAllServerClasses();
     5.1 --- a/extensions/tf2/util.h	Wed Aug 28 13:46:34 2013 -0400
     5.2 +++ b/extensions/tf2/util.h	Thu Aug 29 09:27:35 2013 -0400
     5.3 @@ -49,6 +49,8 @@
     5.4  						  sm_sendprop_info_t *info,
     5.5  						  unsigned int offset);
     5.6  
     5.7 +bool UTIL_ContainsDataTable(SendTable *pTable, const char *name);
     5.8 +
     5.9  ServerClass *UTIL_FindServerClass(const char *classname);
    5.10  
    5.11  CBaseEntity *UTIL_GetCBaseEntity(int num, bool onlyPlayers);
     6.1 --- a/gamedata/sm-tf2.games.txt	Wed Aug 28 13:46:34 2013 -0400
     6.2 +++ b/gamedata/sm-tf2.games.txt	Thu Aug 29 09:27:35 2013 -0400
     6.3 @@ -36,48 +36,6 @@
     6.4  				"linux"		"@_ZN15CTFPlayerShared8DisguiseEiiP9CTFPlayerb"
     6.5  				"mac"		"@_ZN15CTFPlayerShared8DisguiseEiiP9CTFPlayerb"
     6.6  			}
     6.7 -			"CalcCritical"
     6.8 -			{
     6.9 -				"library"	"server"
    6.10 -				"linux"		"@_ZN13CTFWeaponBase26CalcIsAttackCriticalHelperEv"
    6.11 -				"mac"		"@_ZN13CTFWeaponBase26CalcIsAttackCriticalHelperEv"
    6.12 -				"windows"	"\x55\x8B\xEC\x83\xEC\x2A\x56\x57\x6A\x00\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x6A\x00\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x50\xE8\x2A\x2A\x2A\x2A\x8B\xF8\x83\xC4\x2A\x85\xFF\x74\x2A\x8B"
    6.13 -			}
    6.14 -			"CalcCriticalMelee"
    6.15 -			{
    6.16 -				"library"	"server"
    6.17 -				"linux"		"@_ZN18CTFWeaponBaseMelee26CalcIsAttackCriticalHelperEv"
    6.18 -				"mac"		"@_ZN18CTFWeaponBaseMelee26CalcIsAttackCriticalHelperEv"
    6.19 -				"windows"	"\x55\x8B\xEC\x83\xEC\x08\x53\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x8B\xD8\x85\xDB\x74\x10"
    6.20 -			}
    6.21 -			"CalcCriticalBow"
    6.22 -			{
    6.23 -				"library"	"server"
    6.24 -				"linux"		"@_ZN14CTFCompoundBow26CalcIsAttackCriticalHelperEv"
    6.25 -				"mac"		"@_ZN14CTFCompoundBow26CalcIsAttackCriticalHelperEv"
    6.26 -				"windows"	"\xE8\x2A\x2A\x2A\x2A\x85\xC0\x74\x2A\x8D\x88\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x84\xC0\x74\x2A\xB0"
    6.27 -			}
    6.28 -			"CalcCriticalKnife"
    6.29 -			{
    6.30 -				"library"	"server"
    6.31 -				"linux"		"@_ZN8CTFKnife26CalcIsAttackCriticalHelperEv"
    6.32 -				"mac"		"@_ZN8CTFKnife26CalcIsAttackCriticalHelperEv"
    6.33 -				"windows"	"\x8B\x81\x54\x07\x00\x00\x83\xF8\xFF\x74\x2A\x8B\x15\x2A\x2A\x2A\x2A\x8B\xC8\x81\xE1\xFF\x0F\x00\x00\x03\xC9\x8D\x4C\xCA\x04\xC1\xE8\x0C\x39\x41\x04\x75\x2A\x8B\x01"
    6.34 -			}
    6.35 -			"CalcCriticalNoCrits"
    6.36 -			{
    6.37 -				"library"	"server"
    6.38 -				"linux"		"@_ZN13CTFWeaponBase33CalcIsAttackCriticalHelperNoCritsEv"
    6.39 -				"mac"		"@_ZN13CTFWeaponBase33CalcIsAttackCriticalHelperNoCritsEv"
    6.40 -				"windows"	"\x56\x6A\x00\x68\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\x6A\x00\xE8\x2A\x2A\x2A\x2A\x50\xE8\x2A\x2A\x2A\x2A\x8B\xF0\x83\xC4\x14\x85\xF6\x74\x2A"
    6.41 -			}
    6.42 -			"CalcCriticalNoCritsMelee"
    6.43 -			{
    6.44 -				"library"	"server"
    6.45 -				"linux"		"@_ZN18CTFWeaponBaseMelee33CalcIsAttackCriticalHelperNoCritsEv"
    6.46 -				"mac"		"@_ZN18CTFWeaponBaseMelee33CalcIsAttackCriticalHelperNoCritsEv"
    6.47 -				"windows"	"\x56\x57\x8B\xF9\xE8\x2A\x2A\x2A\x2A\x8B\xF0\x85\xF6\x74\x2A\x8B\x06\x8B\x90\x40\x01\x00\x00\x8B\xCE\xFF\xD2\x84\xC0\x75\x2A\x5F\x32\xC0\x5E\xC3\x83\xBE\x80\x1D\x00\x00\x02"
    6.48 -			}
    6.49  			"Regenerate"
    6.50  			{
    6.51  				"library"	"server"
    6.52 @@ -157,6 +115,18 @@
    6.53  				"linux"		"325"
    6.54  				"mac"		"325"
    6.55  			}
    6.56 +			"CalcIsAttackCriticalHelper"
    6.57 +			{
    6.58 +				"windows"	"381"
    6.59 +				"linux"		"388"
    6.60 +				"mac"		"388"
    6.61 +			}
    6.62 +			"CalcIsAttackCriticalHelperNoCrits"
    6.63 +			{
    6.64 +				"windows"	"382"
    6.65 +				"linux"		"389"
    6.66 +				"mac"		"389"
    6.67 +			}
    6.68  		}
    6.69  	}
    6.70  }