extensions/tf2/criticals.cpp
changeset 2136 7e8bf503bc9e
parent 2059 906567c8b63b
child 2600 f78e5656cc6f
     1.1 --- a/extensions/tf2/criticals.cpp	Tue Jul 01 06:13:09 2008 +0000
     1.2 +++ b/extensions/tf2/criticals.cpp	Tue Jul 01 09:04:00 2008 +0000
     1.3 @@ -31,353 +31,46 @@
     1.4  
     1.5  #include "criticals.h"
     1.6  
     1.7 -ISourcePawnEngine *spengine = NULL;
     1.8 -CriticalHitManager g_CriticalHitManager;
     1.9  IServerGameEnts *gameents = NULL;
    1.10  
    1.11 -int g_returnvalue;
    1.12 -
    1.13 -bool CriticalHitManager::CreateCriticalDetour()
    1.14 -{
    1.15 -	if (!g_pGameConf->GetMemSig("CalcCritical", &critical_address) || !critical_address)
    1.16 -	{
    1.17 -		g_pSM->LogError(myself, "Could not locate CalcCritical - Disabling Critical Hit forward");
    1.18 -		return false;
    1.19 -	}
    1.20 -
    1.21 -	if (!g_pGameConf->GetOffset("CalcCriticalBackup", (int *)&(critical_restore.bytes)))
    1.22 -	{
    1.23 -		g_pSM->LogError(myself, "Could not locate CalcCriticalBackup - Disabling Critical Hit forward");
    1.24 -		return false;
    1.25 -	}
    1.26 -
    1.27 -	/* First, save restore bits */
    1.28 -	for (size_t i=0; i<critical_restore.bytes; i++)
    1.29 -	{
    1.30 -		critical_restore.patch[i] = ((unsigned char *)critical_address)[i];
    1.31 -	}
    1.32 -
    1.33 -	critical_callback = spengine->ExecAlloc(100);
    1.34 -	JitWriter wr;
    1.35 -	JitWriter *jit = &wr;
    1.36 -	wr.outbase = (jitcode_t)critical_callback;
    1.37 -	wr.outptr = wr.outbase;
    1.38 -
    1.39 -	/* Function we are detouring into is
    1.40 -	 *
    1.41 -	 * void CriticalDetour(CTFWeaponBase(void *) *pWeapon)
    1.42 -	 *
    1.43 -	 * push		pWeapon [ecx]
    1.44 -	 */
    1.45 +CDetour *calcIsAttackCriticalDetour = NULL;
    1.46 +CDetour *calcIsAttackCriticalMeleeDetour = NULL;
    1.47 +CDetour *calcIsAttackCriticalKnifeDetour = NULL;
    1.48  
    1.49 -#if defined PLATFORM_WINDOWS
    1.50 -	IA32_Push_Reg(jit, REG_ECX);
    1.51 -#elif defined PLATFORM_LINUX
    1.52 -	IA32_Push_Rm_Disp8_ESP(jit, 4);
    1.53 -#endif
    1.54 -
    1.55 -	jitoffs_t call = IA32_Call_Imm32(jit, 0); 
    1.56 -	IA32_Write_Jump32_Abs(jit, call, (void *)TempDetour);
    1.57 -
    1.58 -	
    1.59 -#if defined PLATFORM_LINUX
    1.60 -	IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);		//add esp, 4
    1.61 -#elif defined PLATFORM_WINDOWS
    1.62 -	IA32_Pop_Reg(jit, REG_ECX);
    1.63 -#endif
    1.64 -
    1.65 -	//If TempDetour returns non-zero we want to load something into eax and return this value
    1.66 -
    1.67 -	//test eax, eax
    1.68 -	IA32_Test_Rm_Reg(jit,  REG_EAX, REG_EAX, MOD_REG);
    1.69 -
    1.70 -	//jnz _skip
    1.71 -	jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
    1.72 -
    1.73 -	/* Patch old bytes in */
    1.74 -	for (size_t i=0; i<critical_restore.bytes; i++)
    1.75 -	{
    1.76 -		jit->write_ubyte(critical_restore.patch[i]);
    1.77 -	}
    1.78 -
    1.79 -	/* Return to the original function */
    1.80 -	call = IA32_Jump_Imm32(jit, 0);
    1.81 -	IA32_Write_Jump32_Abs(jit, call, (unsigned char *)critical_address + critical_restore.bytes);
    1.82 -	
    1.83 -	//_skip:
    1.84 -	//mov eax, [g_returnvalue]
    1.85 -	//ret
    1.86 -	IA32_Send_Jump8_Here(jit, jmp);
    1.87 -	IA32_Mov_Eax_Mem(jit, (jit_int32_t)&g_returnvalue);
    1.88 -	IA32_Return(jit);
    1.89 -
    1.90 -	return true;
    1.91 -}
    1.92 +IForward *g_critForward = NULL;
    1.93  
    1.94 -bool CriticalHitManager::CreateCriticalMeleeDetour()
    1.95 +void InitialiseDetours()
    1.96  {
    1.97 -	if (!g_pGameConf->GetMemSig("CalcCriticalMelee", &melee_address) || !melee_address)
    1.98 -	{
    1.99 -		g_pSM->LogError(myself, "Could not locate CalcCriticalMelee - Disabling Critical Hit forward");
   1.100 -		return false;
   1.101 -	}
   1.102 -
   1.103 -	if (!g_pGameConf->GetOffset("CalcCriticalMeleeBackup", (int *)&(melee_restore.bytes)))
   1.104 -	{
   1.105 -		g_pSM->LogError(myself, "Could not locate CalcCriticalMeleeBackup - Disabling Critical Hit forward");
   1.106 -		return false;
   1.107 -	}
   1.108 -
   1.109 -	/* First, save restore bits */
   1.110 -	for (size_t i=0; i<melee_restore.bytes; i++)
   1.111 -	{
   1.112 -		melee_restore.patch[i] = ((unsigned char *)melee_address)[i];
   1.113 -	}
   1.114 -
   1.115 -	melee_callback = spengine->ExecAlloc(100);
   1.116 -	JitWriter wr;
   1.117 -	JitWriter *jit = &wr;
   1.118 -	wr.outbase = (jitcode_t)melee_callback;
   1.119 -	wr.outptr = wr.outbase;
   1.120 -
   1.121 -	/* Function we are detouring into is
   1.122 -	 *
   1.123 -	 * void CriticalDetour(CTFWeaponBase(void *) *pWeapon)
   1.124 -	 *
   1.125 -	 * push		pWeapon [ecx]
   1.126 -	 */
   1.127 -
   1.128 -#if defined PLATFORM_WINDOWS
   1.129 -	IA32_Push_Reg(jit, REG_ECX);
   1.130 -#elif defined PLATFORM_LINUX
   1.131 -	IA32_Push_Rm_Disp8_ESP(jit, 4);
   1.132 -#endif
   1.133 +	calcIsAttackCriticalDetour = CDetourManager::CreateDetour((void *)&TempDetour, 0, "CalcCritical");
   1.134 +	calcIsAttackCriticalMeleeDetour = CDetourManager::CreateDetour((void *)&TempDetour, 0, "CalcCriticalMelee");
   1.135 +	calcIsAttackCriticalKnifeDetour = CDetourManager::CreateDetour((void *)&TempDetour, 0, "CalcCriticalKnife");
   1.136  
   1.137 -	jitoffs_t call = IA32_Call_Imm32(jit, 0); 
   1.138 -	IA32_Write_Jump32_Abs(jit, call, (void *)TempDetour);
   1.139 -
   1.140 -	
   1.141 -#if defined PLATFORM_LINUX
   1.142 -	IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);		//add esp, 4
   1.143 -#elif defined PLATFORM_WINDOWS
   1.144 -	IA32_Pop_Reg(jit, REG_ECX);
   1.145 -#endif
   1.146 -
   1.147 -	//If TempDetour returns non-zero we want to load something into eax and return this value
   1.148 -
   1.149 -	//test eax, eax
   1.150 -	IA32_Test_Rm_Reg(jit,  REG_EAX, REG_EAX, MOD_REG);
   1.151 -
   1.152 -	//jnz _skip
   1.153 -	jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
   1.154 +	bool HookCreated = false;
   1.155  
   1.156 -	int callbyte = -1;
   1.157 -	/* The callbyte should return the nth byte (starting from 1) in the backup bytes - Should be an 0xE8 (call) */
   1.158 -	g_pGameConf->GetOffset("CalcCriticalMeleeCallByte", &callbyte);
   1.159 -
   1.160 -	callbyte--;
   1.161 -	void *function = NULL;
   1.162 -
   1.163 -	if (callbyte > -1)
   1.164 +	if (calcIsAttackCriticalDetour != NULL)
   1.165  	{
   1.166 -		/* Check if the 'callbyte' is actually a call */
   1.167 -		if (melee_restore.patch[callbyte] != 0xE8)
   1.168 -		{
   1.169 -			g_pSM->LogError(myself, "Invalid callbyte - Melee detour may work incorrectly");
   1.170 -		}
   1.171 -		else
   1.172 -		{
   1.173 -			/* Find the absolute address of the function it calls */
   1.174 -			void *offsetaddr = (void *)((unsigned char *)melee_address + callbyte + 1);
   1.175 -			int offset = (int)*(unsigned char *)offsetaddr;
   1.176 -			function = (unsigned char *)offsetaddr + offset + 4;
   1.177 -		}
   1.178 +		calcIsAttackCriticalDetour->EnableDetour();
   1.179 +		HookCreated = true;
   1.180  	}
   1.181  
   1.182 -	/* Patch old bytes in */
   1.183 -	for (size_t i=0; i<melee_restore.bytes; i++)
   1.184 +	if (calcIsAttackCriticalMeleeDetour != NULL)
   1.185  	{
   1.186 -		if ((int)i != callbyte)
   1.187 -		{
   1.188 -			jit->write_ubyte(melee_restore.patch[i]);
   1.189 -			continue;
   1.190 -		}
   1.191 -		
   1.192 -		/* Write in the adjusted call instead */
   1.193 -		jitoffs_t call = IA32_Call_Imm32(jit, 0); 
   1.194 -		IA32_Write_Jump32_Abs(jit, call, function);
   1.195 -
   1.196 -		i += 4;
   1.197 -	}
   1.198 -
   1.199 -	/* Return to the original function */
   1.200 -	call = IA32_Jump_Imm32(jit, 0);
   1.201 -	IA32_Write_Jump32_Abs(jit, call, (unsigned char *)melee_address + melee_restore.bytes);
   1.202 -	
   1.203 -	//_skip:
   1.204 -	//mov eax, [g_returnvalue]
   1.205 -	//ret
   1.206 -	IA32_Send_Jump8_Here(jit, jmp);
   1.207 -	IA32_Mov_Eax_Mem(jit, (jit_int32_t)&g_returnvalue);
   1.208 -	IA32_Return(jit);
   1.209 -
   1.210 -	return true;
   1.211 -}
   1.212 -
   1.213 -bool CriticalHitManager::CreateCriticalKnifeDetour()
   1.214 -{
   1.215 -	if (!g_pGameConf->GetMemSig("CalcCriticalKnife", &knife_address) || !knife_address)
   1.216 -	{
   1.217 -		g_pSM->LogError(myself, "Could not locate CalcCriticalKnife - Disabling Critical Hit forward");
   1.218 -		return false;
   1.219 -	}
   1.220 -
   1.221 -	if (!g_pGameConf->GetOffset("CalcCriticalKnifeBackup", (int *)&(knife_restore.bytes)))
   1.222 -	{
   1.223 -		g_pSM->LogError(myself, "Could not locate CalcCriticalKnifeBackup - Disabling Critical Hit forward");
   1.224 -		return false;
   1.225 -	}
   1.226 -
   1.227 -	/* First, save restore bits */
   1.228 -	for (size_t i=0; i<knife_restore.bytes; i++)
   1.229 -	{
   1.230 -		knife_restore.patch[i] = ((unsigned char *)knife_address)[i];
   1.231 +		calcIsAttackCriticalMeleeDetour->EnableDetour();
   1.232 +		HookCreated = true;
   1.233  	}
   1.234  
   1.235 -	knife_callback = spengine->ExecAlloc(100);
   1.236 -	JitWriter wr;
   1.237 -	JitWriter *jit = &wr;
   1.238 -	wr.outbase = (jitcode_t)knife_callback;
   1.239 -	wr.outptr = wr.outbase;
   1.240 -
   1.241 -	/* Function we are detouring into is
   1.242 -	 *
   1.243 -	 * void CriticalDetour(CTFWeaponBase(void *) *pWeapon)
   1.244 -	 *
   1.245 -	 * push		pWeapon [ecx]
   1.246 -	 */
   1.247 -
   1.248 -#if defined PLATFORM_WINDOWS
   1.249 -	IA32_Push_Reg(jit, REG_ECX);
   1.250 -#elif defined PLATFORM_LINUX
   1.251 -	IA32_Push_Rm_Disp8_ESP(jit, 4);
   1.252 -#endif
   1.253 -
   1.254 -	jitoffs_t call = IA32_Call_Imm32(jit, 0); 
   1.255 -	IA32_Write_Jump32_Abs(jit, call, (void *)TempDetour);
   1.256 -
   1.257 -	
   1.258 -#if defined PLATFORM_LINUX
   1.259 -	IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);		//add esp, 4
   1.260 -#elif defined PLATFORM_WINDOWS
   1.261 -	IA32_Pop_Reg(jit, REG_ECX);
   1.262 -#endif
   1.263 -
   1.264 -	//If TempDetour returns non-zero we want to load something into eax and return this value
   1.265 -
   1.266 -	//test eax, eax
   1.267 -	IA32_Test_Rm_Reg(jit,  REG_EAX, REG_EAX, MOD_REG);
   1.268 -
   1.269 -	//jnz _skip
   1.270 -	jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
   1.271 -
   1.272 -	/* Patch old bytes in */
   1.273 -	for (size_t i=0; i<knife_restore.bytes; i++)
   1.274 +	if (calcIsAttackCriticalKnifeDetour != NULL)
   1.275  	{
   1.276 -		jit->write_ubyte(knife_restore.patch[i]);
   1.277 +		calcIsAttackCriticalKnifeDetour->EnableDetour();
   1.278 +		HookCreated = true;
   1.279  	}
   1.280  
   1.281 -	/* Return to the original function */
   1.282 -	call = IA32_Jump_Imm32(jit, 0);
   1.283 -	IA32_Write_Jump32_Abs(jit, call, (unsigned char *)knife_address + knife_restore.bytes);
   1.284 -	
   1.285 -	//_skip:
   1.286 -	//mov eax, [g_returnvalue]
   1.287 -	//ret
   1.288 -	IA32_Send_Jump8_Here(jit, jmp);
   1.289 -	IA32_Mov_Eax_Mem(jit, (jit_int32_t)&g_returnvalue);
   1.290 -	IA32_Return(jit);
   1.291 -
   1.292 -	return true;
   1.293 -}
   1.294 -
   1.295 -void CriticalHitManager::EnableCriticalDetour()
   1.296 -{
   1.297 -	if (!detoured)
   1.298 +	if (!HookCreated)
   1.299  	{
   1.300 -		if (normalcreated)
   1.301 -		{
   1.302 -			DoGatePatch((unsigned char *)critical_address, &critical_callback);
   1.303 -		}
   1.304 -		if (meleecreated)
   1.305 -		{
   1.306 -			DoGatePatch((unsigned char *)melee_address, &melee_callback);
   1.307 -		}
   1.308 -		if (knifecreated)
   1.309 -		{
   1.310 -			DoGatePatch((unsigned char *)knife_address, &knife_callback);
   1.311 -		}
   1.312 -
   1.313 -		detoured = true;
   1.314 -	}
   1.315 -}
   1.316 -
   1.317 -void CriticalHitManager::DeleteCriticalDetour()
   1.318 -{
   1.319 -	if (detoured)
   1.320 -	{
   1.321 -		DisableCriticalDetour();
   1.322 +		g_pSM->LogError(myself, "No critical hit forwards could be initialized - Disabled critical hit hooks");
   1.323 +		return;
   1.324  	}
   1.325  
   1.326 -	if (critical_callback)
   1.327 -	{
   1.328 -		/* Free the gate */
   1.329 -		spengine->ExecFree(critical_callback);
   1.330 -		critical_callback = NULL;
   1.331 -	}
   1.332 -
   1.333 -	if (melee_callback)
   1.334 -	{
   1.335 -		/* Free the gate */
   1.336 -		spengine->ExecFree(melee_callback);
   1.337 -		melee_callback = NULL;
   1.338 -	}
   1.339 -
   1.340 -	if (knife_callback)
   1.341 -	{
   1.342 -		/* Free the gate */
   1.343 -		spengine->ExecFree(knife_callback);
   1.344 -		knife_callback = NULL;
   1.345 -	}
   1.346 -}
   1.347 -
   1.348 -bool TempDetour(void *pWeapon)
   1.349 -{
   1.350 -	return g_CriticalHitManager.CriticalDetour(pWeapon);
   1.351 -}
   1.352 -
   1.353 -void CriticalHitManager::DisableCriticalDetour()
   1.354 -{
   1.355 -	if (critical_callback)
   1.356 -	{
   1.357 -		/* Remove the patch */
   1.358 -		ApplyPatch(critical_address, 0, &critical_restore, NULL);
   1.359 -		detoured = false;
   1.360 -	}
   1.361 -
   1.362 -	if (melee_callback)
   1.363 -	{
   1.364 -		/* Remove the patch */
   1.365 -		ApplyPatch(melee_address, 0, &melee_restore, NULL);
   1.366 -		detoured = false;
   1.367 -	}
   1.368 -
   1.369 -	if (knife_callback)
   1.370 -	{
   1.371 -		/* Remove the patch */
   1.372 -		ApplyPatch(knife_address, 0, &knife_restore, NULL);
   1.373 -		detoured = false;
   1.374 -	}
   1.375  }
   1.376  
   1.377  int CheckBaseHandle(CBaseHandle &hndl)
   1.378 @@ -413,7 +106,7 @@
   1.379  	return index;
   1.380  }
   1.381  
   1.382 -bool CriticalHitManager::CriticalDetour(void *pWeapon)
   1.383 +DetourReturn TempDetour(void *pWeapon)
   1.384  {
   1.385  	edict_t *pEdict = gameents->BaseEntityToEdict((CBaseEntity *)pWeapon);
   1.386  	
   1.387 @@ -431,23 +124,40 @@
   1.388  		return false;
   1.389  	}
   1.390  
   1.391 -	if (!forward)
   1.392 +	if (!g_critForward)
   1.393  	{
   1.394  		g_pSM->LogMessage(myself, "Invalid Forward");
   1.395  		return false;
   1.396  	}
   1.397 +
   1.398 +	int returnValue=0;
   1.399  	
   1.400  	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pWeapon + info.actual_offset);
   1.401  	int index = CheckBaseHandle(hndl);
   1.402  
   1.403 -	forward->PushCell(index); //Client index
   1.404 -	forward->PushCell(engine->IndexOfEdict(pEdict)); // Weapon index
   1.405 -	forward->PushString(pEdict->GetClassName()); //Weapon classname
   1.406 -	forward->PushCellByRef(&g_returnvalue); //return value
   1.407 +	g_critForward->PushCell(index); //Client index
   1.408 +	g_critForward->PushCell(engine->IndexOfEdict(pEdict)); // Weapon index
   1.409 +	g_critForward->PushString(pEdict->GetClassName()); //Weapon classname
   1.410 +	g_critForward->PushCellByRef(&returnValue); //return value
   1.411  
   1.412  	cell_t result = 0;
   1.413  
   1.414 -	forward->Execute(&result);
   1.415 +	g_critForward->Execute(&result);
   1.416  
   1.417 -	return !!result;
   1.418 +	if (result)
   1.419 +	{
   1.420 +		RETURN_DETOUR_VALUE(DETOUR_RESULT_OVERRIDE, returnValue);
   1.421 +	}
   1.422 +	else
   1.423 +	{
   1.424 +		RETURN_DETOUR_VALUE(DETOUR_RESULT_IGNORED, returnValue);
   1.425 +	}
   1.426 +	
   1.427  }
   1.428 +
   1.429 +void RemoveDetours()
   1.430 +{
   1.431 +	CDetourManager::DeleteDetour(calcIsAttackCriticalDetour);
   1.432 +	CDetourManager::DeleteDetour(calcIsAttackCriticalMeleeDetour);
   1.433 +	CDetourManager::DeleteDetour(calcIsAttackCriticalKnifeDetour);
   1.434 +}