extensions/tf2/criticals.cpp
changeset 4092 f184c016f489
parent 4001 608bc5be1ef0
child 4093 da128cd7be77
     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  }