Big critical hits cleanup. Cleaner, easier to maintain, uses less memory and should be much less likely to cause crashes when valve change things on me.
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%402317
This commit is contained in:
parent
b01dd0798c
commit
d530d0c726
@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* vim: set ts=4 :
|
* vim: set ts=4 :
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
* SourceMod Team Fortress 2 Extension
|
* SourceMod SDKTools Extension
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
@ -29,8 +29,8 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _INCLUDE_SOURCEMOD_DETOURS_H_
|
#ifndef _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
||||||
#define _INCLUDE_SOURCEMOD_DETOURS_H_
|
#define _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
||||||
|
|
||||||
#if defined PLATFORM_LINUX
|
#if defined PLATFORM_LINUX
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
@ -95,4 +95,4 @@ inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_DETOURS_H_
|
#endif //_INCLUDE_SOURCEMOD_DETOURHELPERS_H_
|
341
extensions/tf2/CDetour/detours.cpp
Normal file
341
extensions/tf2/CDetour/detours.cpp
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
#include "detours.h"
|
||||||
|
#include <asm/asm.h>
|
||||||
|
|
||||||
|
ISourcePawnEngine *CDetourManager::spengine = NULL;
|
||||||
|
IGameConfig *CDetourManager::gameconf = NULL;
|
||||||
|
int CDetourManager::returnValue = 0;
|
||||||
|
|
||||||
|
void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
|
||||||
|
{
|
||||||
|
CDetourManager::spengine = spengine;
|
||||||
|
CDetourManager::gameconf = gameconf;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDetour *CDetourManager::CreateDetour(void *callbackfunction, size_t paramsize, const char *signame)
|
||||||
|
{
|
||||||
|
CDetour *detour = new CDetour(callbackfunction, paramsize, signame);
|
||||||
|
if (detour)
|
||||||
|
{
|
||||||
|
if (!detour->Init(spengine, gameconf))
|
||||||
|
{
|
||||||
|
delete detour;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return detour;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDetourManager::DeleteDetour(CDetour *detour)
|
||||||
|
{
|
||||||
|
delete detour;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBlocker * CDetourManager::CreateFunctionBlock( const char *signame, bool isVoid )
|
||||||
|
{
|
||||||
|
CBlocker *block = new CBlocker(signame, isVoid);
|
||||||
|
|
||||||
|
if (block)
|
||||||
|
{
|
||||||
|
if (!block->Init(spengine, gameconf))
|
||||||
|
{
|
||||||
|
delete block;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDetourManager::DeleteFunctionBlock(CBlocker *block)
|
||||||
|
{
|
||||||
|
delete block;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDetour::CDetour(void *callbackfunction, size_t paramsize, const char *signame)
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
detoured = false;
|
||||||
|
detour_address = NULL;
|
||||||
|
detour_callback = NULL;
|
||||||
|
this->signame = signame;
|
||||||
|
this->callbackfunction = callbackfunction;
|
||||||
|
spengine = NULL;
|
||||||
|
gameconf = NULL;
|
||||||
|
this->paramsize = paramsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDetour::~CDetour()
|
||||||
|
{
|
||||||
|
DeleteDetour();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
|
||||||
|
{
|
||||||
|
this->spengine = spengine;
|
||||||
|
this->gameconf = gameconf;
|
||||||
|
|
||||||
|
if (!CreateDetour())
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
enabled = true;
|
||||||
|
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDetour::IsEnabled()
|
||||||
|
{
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDetour::CreateDetour()
|
||||||
|
{
|
||||||
|
if (!gameconf->GetMemSig(signame, &detour_address))
|
||||||
|
{
|
||||||
|
g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!detour_address)
|
||||||
|
{
|
||||||
|
g_pSM->LogError(myself, "Sigscan for %s failed - Disabling detour", signame);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE);
|
||||||
|
|
||||||
|
/* First, save restore bits */
|
||||||
|
for (size_t i=0; i<detour_restore.bytes; i++)
|
||||||
|
{
|
||||||
|
detour_restore.patch[i] = ((unsigned char *)detour_address)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//detour_callback = spengine->ExecAlloc(100);
|
||||||
|
JitWriter wr;
|
||||||
|
JitWriter *jit = ≀
|
||||||
|
jit_uint32_t CodeSize = 0;
|
||||||
|
|
||||||
|
wr.outbase = NULL;
|
||||||
|
wr.outptr = NULL;
|
||||||
|
|
||||||
|
jit_rewind:
|
||||||
|
|
||||||
|
/* Push all our params onto the stack */
|
||||||
|
for (size_t i=0; i<paramsize; i++)
|
||||||
|
{
|
||||||
|
#if defined PLATFORM_WINDOWS
|
||||||
|
IA32_Push_Rm_Disp8_ESP(jit, (paramsize*4));
|
||||||
|
#elif defined PLATFORM_LINUX
|
||||||
|
IA32_Push_Rm_Disp8_ESP(jit, 4 +(paramsize*4));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push thisptr onto the stack */
|
||||||
|
#if defined PLATFORM_WINDOWS
|
||||||
|
IA32_Push_Reg(jit, REG_ECX);
|
||||||
|
#elif defined PLATFORM_LINUX
|
||||||
|
IA32_Push_Rm_Disp8_ESP(jit, 4 + (paramsize*4));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
||||||
|
IA32_Write_Jump32_Abs(jit, call, callbackfunction);
|
||||||
|
|
||||||
|
/* Pop thisptr */
|
||||||
|
#if defined PLATFORM_LINUX
|
||||||
|
IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); //add esp, 4
|
||||||
|
#elif defined PLATFORM_WINDOWS
|
||||||
|
IA32_Pop_Reg(jit, REG_ECX);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Pop params from the stack */
|
||||||
|
for (size_t i=0; i<paramsize; i++)
|
||||||
|
{
|
||||||
|
IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
//If TempDetour returns non-zero we want to load something into eax and return this value
|
||||||
|
|
||||||
|
//test eax, eax
|
||||||
|
IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG);
|
||||||
|
|
||||||
|
//jnz _skip
|
||||||
|
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
|
||||||
|
|
||||||
|
/* Patch old bytes in */
|
||||||
|
if (wr.outbase != NULL)
|
||||||
|
{
|
||||||
|
copy_bytes((unsigned char *)detour_address, (unsigned char*)wr.outptr, detour_restore.bytes);
|
||||||
|
}
|
||||||
|
wr.outptr += detour_restore.bytes;
|
||||||
|
|
||||||
|
/* Return to the original function */
|
||||||
|
call = IA32_Jump_Imm32(jit, 0);
|
||||||
|
IA32_Write_Jump32_Abs(jit, call, (unsigned char *)detour_address + detour_restore.bytes);
|
||||||
|
|
||||||
|
//_skip:
|
||||||
|
//mov eax, [g_returnvalue]
|
||||||
|
//ret
|
||||||
|
IA32_Send_Jump8_Here(jit, jmp);
|
||||||
|
IA32_Mov_Eax_Mem(jit, (jit_int32_t)&CDetourManager::returnValue);
|
||||||
|
IA32_Return(jit);
|
||||||
|
|
||||||
|
if (wr.outbase == NULL)
|
||||||
|
{
|
||||||
|
CodeSize = wr.get_outputpos();
|
||||||
|
wr.outbase = (jitcode_t)spengine->AllocatePageMemory(CodeSize);
|
||||||
|
spengine->SetReadWrite(wr.outbase);
|
||||||
|
wr.outptr = wr.outbase;
|
||||||
|
detour_callback = wr.outbase;
|
||||||
|
goto jit_rewind;
|
||||||
|
}
|
||||||
|
|
||||||
|
spengine->SetReadExecute(wr.outbase);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDetour::EnableDetour()
|
||||||
|
{
|
||||||
|
if (!detoured)
|
||||||
|
{
|
||||||
|
DoGatePatch((unsigned char *)detour_address, &detour_callback);
|
||||||
|
detoured = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDetour::DeleteDetour()
|
||||||
|
{
|
||||||
|
if (detoured)
|
||||||
|
{
|
||||||
|
DisableDetour();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detour_callback)
|
||||||
|
{
|
||||||
|
/* Free the gate */
|
||||||
|
spengine->ExecFree(detour_callback);
|
||||||
|
detour_callback = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDetour::DisableDetour()
|
||||||
|
{
|
||||||
|
if (detoured)
|
||||||
|
{
|
||||||
|
/* Remove the patch */
|
||||||
|
/* This may screw up */
|
||||||
|
ApplyPatch(detour_address, 0, &detour_restore, NULL);
|
||||||
|
detoured = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CBlocker::CBlocker( const char *signame, bool isVoid )
|
||||||
|
{
|
||||||
|
this->isVoid = isVoid;
|
||||||
|
isEnabled = false;
|
||||||
|
isValid = false;
|
||||||
|
|
||||||
|
spengine = NULL;
|
||||||
|
gameconf = NULL;
|
||||||
|
block_address = NULL;
|
||||||
|
block_sig = signame;
|
||||||
|
|
||||||
|
if (isVoid)
|
||||||
|
{
|
||||||
|
/* Void functions we only patch in a 'ret' (1 byte) */
|
||||||
|
block_restore.bytes = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Normal functions need an mov eax, value */
|
||||||
|
block_restore.bytes = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBlocker::EnableBlock( int returnValue )
|
||||||
|
{
|
||||||
|
if (!isValid || isEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First, save restore bits */
|
||||||
|
for (size_t i=0; i<block_restore.bytes; i++)
|
||||||
|
{
|
||||||
|
block_restore.patch[i] = ((unsigned char *)block_address)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
JitWriter wr;
|
||||||
|
JitWriter *jit = ≀
|
||||||
|
wr.outbase = (jitcode_t)block_address;
|
||||||
|
wr.outptr = wr.outbase;
|
||||||
|
|
||||||
|
if (isVoid)
|
||||||
|
{
|
||||||
|
IA32_Return(jit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IA32_Mov_Reg_Imm32(jit, REG_EAX, returnValue);
|
||||||
|
IA32_Return(jit);
|
||||||
|
}
|
||||||
|
|
||||||
|
isEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBlocker::DisableBlock()
|
||||||
|
{
|
||||||
|
if (!isValid || !isEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First, save restore bits */
|
||||||
|
for (size_t i=0; i<block_restore.bytes; i++)
|
||||||
|
{
|
||||||
|
((unsigned char *)block_address)[i] = block_restore.patch[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
isEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBlocker::~CBlocker()
|
||||||
|
{
|
||||||
|
if (!isValid || !isEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisableBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CBlocker::Init( ISourcePawnEngine *spengine, IGameConfig *gameconf )
|
||||||
|
{
|
||||||
|
this->spengine = spengine;
|
||||||
|
this->gameconf = gameconf;
|
||||||
|
|
||||||
|
if (!gameconf->GetMemSig(block_sig, &block_address))
|
||||||
|
{
|
||||||
|
g_pSM->LogError(myself, "Could not locate %s - Disabling blocker", block_sig);
|
||||||
|
isValid = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!block_address)
|
||||||
|
{
|
||||||
|
g_pSM->LogError(myself, "Sigscan for %s failed - Disabling blocker", block_sig);
|
||||||
|
isValid = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
166
extensions/tf2/CDetour/detours.h
Normal file
166
extensions/tf2/CDetour/detours.h
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_DETOURS_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_DETOURS_H_
|
||||||
|
|
||||||
|
#include "extension.h"
|
||||||
|
#include <jit/jit_helpers.h>
|
||||||
|
#include <jit/x86/x86_macros.h>
|
||||||
|
#include "detourhelpers.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CDetours class for SourceMod Extensions by pRED*
|
||||||
|
* detourhelpers.h entirely stolen from CSS:DM and were written by BAILOPAN (I assume).
|
||||||
|
* asm.h/c from devmaster.net (thanks cybermind)
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CDetourManager;
|
||||||
|
|
||||||
|
class CDetour
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool IsEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These would be somewhat self-explanatory I hope
|
||||||
|
*/
|
||||||
|
void EnableDetour();
|
||||||
|
void DisableDetour();
|
||||||
|
|
||||||
|
friend class CDetourManager;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CDetour(void *callbackfunction, size_t paramsize, const char *signame);
|
||||||
|
~CDetour();
|
||||||
|
|
||||||
|
bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
|
||||||
|
private:
|
||||||
|
|
||||||
|
/* These create/delete the allocated memory */
|
||||||
|
bool CreateDetour();
|
||||||
|
void DeleteDetour();
|
||||||
|
|
||||||
|
bool enabled;
|
||||||
|
bool detoured;
|
||||||
|
|
||||||
|
patch_t detour_restore;
|
||||||
|
void *detour_address;
|
||||||
|
void *detour_callback;
|
||||||
|
|
||||||
|
const char *signame;
|
||||||
|
|
||||||
|
void *callbackfunction;
|
||||||
|
|
||||||
|
size_t paramsize;
|
||||||
|
|
||||||
|
ISourcePawnEngine *spengine;
|
||||||
|
IGameConfig *gameconf;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CBlocker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void EnableBlock(int returnValue = 0);
|
||||||
|
void DisableBlock();
|
||||||
|
|
||||||
|
friend class CDetourManager;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CBlocker(const char *signame, bool isVoid);
|
||||||
|
~CBlocker();
|
||||||
|
|
||||||
|
bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isValid;
|
||||||
|
bool isEnabled;
|
||||||
|
bool isVoid;
|
||||||
|
patch_t block_restore;
|
||||||
|
void *block_address;
|
||||||
|
|
||||||
|
const char *block_sig;
|
||||||
|
|
||||||
|
ISourcePawnEngine *spengine;
|
||||||
|
IGameConfig *gameconf;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CDetourManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return Types for Detours
|
||||||
|
*/
|
||||||
|
enum DetourReturn
|
||||||
|
{
|
||||||
|
DetourReturn_Ignored = 0, /** Ignore our result and let the original function run */
|
||||||
|
DetourReturn_Override = 1, /** Block the original function from running and use our return value */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new detour
|
||||||
|
* @param callbackfunction Void pointer to your detour callback function. This should be a static function.
|
||||||
|
* It should have pointer to the thisptr as the first param and then the same params
|
||||||
|
* as the original function. Use void * for unknown types.
|
||||||
|
* @param paramsize This is usually the number of params the function has (not including thisptr). If the function
|
||||||
|
* passes complex types by value you need to add the sizeof() the type (aligned to 4 bytes).
|
||||||
|
* Ie: passing something of size 8 would count as 2 in the param count.
|
||||||
|
* @param signame Section name containing a signature to fetch from the gamedata file.
|
||||||
|
* @return A new CDetour pointer to control your detour.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int)
|
||||||
|
*
|
||||||
|
* Callback:
|
||||||
|
* DetourReturn ConnectClientDetour(void *CBaseServer, void *netaddr_s, int something, int something2, int something3, char const* name, char const* pass, const char* steamcert, int len);
|
||||||
|
*
|
||||||
|
* Creation:
|
||||||
|
* CDetourManager::CreateDetour((void *)&ConnectClientDetour, 8, "ConnectClient");
|
||||||
|
*/
|
||||||
|
static CDetour *CreateDetour(void *callbackfunction, size_t paramsize, const char *signame);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a detour
|
||||||
|
*/
|
||||||
|
static void DeleteDetour(CDetour *detour);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a function blocker. This is slightly faster than a detour because it avoids a call.
|
||||||
|
*
|
||||||
|
* @param signame Section name containing a signature to fetch from the gamedata file.
|
||||||
|
* @param isVoid Specifies if the function can return void.
|
||||||
|
*/
|
||||||
|
static CBlocker *CreateFunctionBlock(const char *signame, bool isVoid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a function blocker.
|
||||||
|
*/
|
||||||
|
static void DeleteFunctionBlock(CBlocker *block);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global DetourReturn value to use for the current hook
|
||||||
|
*/
|
||||||
|
static int returnValue;
|
||||||
|
|
||||||
|
friend class CBlocker;
|
||||||
|
friend class CDetour;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ISourcePawnEngine *spengine;
|
||||||
|
static IGameConfig *gameconf;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef bool DetourReturn;
|
||||||
|
|
||||||
|
#define DETOUR_RESULT_IGNORED false
|
||||||
|
#define DETOUR_RESULT_OVERRIDE true
|
||||||
|
|
||||||
|
#define SET_DETOUR_RETURN_VALUE(value) CDetourManager::returnValue=(int)value
|
||||||
|
#define RETURN_DETOUR(result) return result
|
||||||
|
#define RETURN_DETOUR_VALUE(result,value) do { SET_DETOUR_RETURN_VALUE(value); return (result); } while(0)
|
||||||
|
|
||||||
|
#endif // _INCLUDE_SOURCEMOD_DETOURS_H_
|
@ -18,7 +18,7 @@ PROJECT = game.tf2
|
|||||||
USEMETA = true
|
USEMETA = true
|
||||||
|
|
||||||
OBJECTS = sdk/smsdk_ext.cpp extension.cpp natives.cpp RegNatives.cpp criticals.cpp \
|
OBJECTS = sdk/smsdk_ext.cpp extension.cpp natives.cpp RegNatives.cpp criticals.cpp \
|
||||||
util.cpp
|
util.cpp CDetour/detours.cpp asm/asm.c
|
||||||
|
|
||||||
##############################################
|
##############################################
|
||||||
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
||||||
@ -43,7 +43,7 @@ endif
|
|||||||
ifeq "$(ENGINE)" "orangebox"
|
ifeq "$(ENGINE)" "orangebox"
|
||||||
HL2SDK = $(HL2SDK_OB)
|
HL2SDK = $(HL2SDK_OB)
|
||||||
HL2PUB = $(HL2SDK_OB)/public
|
HL2PUB = $(HL2SDK_OB)/public
|
||||||
HL2LIB = $(HL2SDK_OB)/linux_sdk
|
HL2LIB = $(HL2SDK_OB)/lib/linux
|
||||||
CFLAGS += -DORANGEBOX_BUILD
|
CFLAGS += -DORANGEBOX_BUILD
|
||||||
METAMOD = $(SOURCEMM16)
|
METAMOD = $(SOURCEMM16)
|
||||||
INCLUDE += -I$(HL2SDK)/public/game/server
|
INCLUDE += -I$(HL2SDK)/public/game/server
|
||||||
@ -101,6 +101,8 @@ $(BIN_DIR)/%.o: %.cpp
|
|||||||
|
|
||||||
all: check
|
all: check
|
||||||
mkdir -p $(BIN_DIR)/sdk
|
mkdir -p $(BIN_DIR)/sdk
|
||||||
|
mkdir -p $(BIN_DIR)/CDetour
|
||||||
|
mkdir -p $(BIN_DIR)/asm
|
||||||
if [ "$(USEMETA)" == "true" ]; then \
|
if [ "$(USEMETA)" == "true" ]; then \
|
||||||
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so; \
|
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so; \
|
||||||
fi
|
fi
|
||||||
|
329
extensions/tf2/asm/asm.c
Normal file
329
extensions/tf2/asm/asm.c
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
#include "asm.h"
|
||||||
|
|
||||||
|
//if dest is NULL, returns minimum number of bytes needed to be copied
|
||||||
|
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
|
||||||
|
//http://www.devmaster.net/forums/showthread.php?t=2311
|
||||||
|
int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) {
|
||||||
|
int bytecount = 0;
|
||||||
|
|
||||||
|
while(bytecount < required_len && *func != 0xCC)
|
||||||
|
{
|
||||||
|
// prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h
|
||||||
|
int operandSize = 4;
|
||||||
|
int FPU = 0;
|
||||||
|
int twoByte = 0;
|
||||||
|
unsigned char opcode = 0x90;
|
||||||
|
unsigned char modRM = 0xFF;
|
||||||
|
while(*func == 0xF0 ||
|
||||||
|
*func == 0xF2 ||
|
||||||
|
*func == 0xF3 ||
|
||||||
|
(*func & 0xFC) == 0x64 ||
|
||||||
|
(*func & 0xF8) == 0xD8 ||
|
||||||
|
(*func & 0x7E) == 0x62)
|
||||||
|
{
|
||||||
|
if(*func == 0x66)
|
||||||
|
{
|
||||||
|
operandSize = 2;
|
||||||
|
}
|
||||||
|
else if((*func & 0xF8) == 0xD8)
|
||||||
|
{
|
||||||
|
FPU = *func;
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// two-byte opcode byte
|
||||||
|
if(*func == 0x0F)
|
||||||
|
{
|
||||||
|
twoByte = 1;
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// opcode byte
|
||||||
|
opcode = *func++;
|
||||||
|
if (dest) *dest++ = opcode;
|
||||||
|
bytecount++;
|
||||||
|
|
||||||
|
// mod R/M byte
|
||||||
|
modRM = 0xFF;
|
||||||
|
if(FPU)
|
||||||
|
{
|
||||||
|
if((opcode & 0xC0) != 0xC0)
|
||||||
|
{
|
||||||
|
modRM = opcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(!twoByte)
|
||||||
|
{
|
||||||
|
if((opcode & 0xC4) == 0x00 ||
|
||||||
|
(opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09) ||
|
||||||
|
(opcode & 0xF0) == 0x80 ||
|
||||||
|
(opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02 ||
|
||||||
|
(opcode & 0xFC) == 0xD0 ||
|
||||||
|
(opcode & 0xF6) == 0xF6)
|
||||||
|
{
|
||||||
|
modRM = *func++;
|
||||||
|
if (dest) *dest++ = modRM;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D ||
|
||||||
|
(opcode & 0xF0) == 0x30 ||
|
||||||
|
opcode == 0x77 ||
|
||||||
|
(opcode & 0xF0) == 0x80 ||
|
||||||
|
(opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02 ||
|
||||||
|
(opcode & 0xF8) == 0xC8)
|
||||||
|
{
|
||||||
|
// No mod R/M byte
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modRM = *func++;
|
||||||
|
if (dest) *dest++ = modRM;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIB
|
||||||
|
if((modRM & 0x07) == 0x04 &&
|
||||||
|
(modRM & 0xC0) != 0xC0)
|
||||||
|
{
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++; //SIB
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mod R/M displacement
|
||||||
|
|
||||||
|
// Dword displacement, no base
|
||||||
|
if((modRM & 0xC5) == 0x05) {
|
||||||
|
if (dest) {
|
||||||
|
*(unsigned int*)dest = *(unsigned int*)func;
|
||||||
|
dest += 4;
|
||||||
|
}
|
||||||
|
func += 4;
|
||||||
|
bytecount += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte displacement
|
||||||
|
if((modRM & 0xC0) == 0x40) {
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dword displacement
|
||||||
|
if((modRM & 0xC0) == 0x80) {
|
||||||
|
if (dest) {
|
||||||
|
*(unsigned int*)dest = *(unsigned int*)func;
|
||||||
|
dest += 4;
|
||||||
|
}
|
||||||
|
func += 4;
|
||||||
|
bytecount += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// immediate
|
||||||
|
if(FPU)
|
||||||
|
{
|
||||||
|
// Can't have immediate operand
|
||||||
|
}
|
||||||
|
else if(!twoByte)
|
||||||
|
{
|
||||||
|
if((opcode & 0xC7) == 0x04 ||
|
||||||
|
(opcode & 0xFE) == 0x6A || // PUSH/POP/IMUL
|
||||||
|
(opcode & 0xF0) == 0x70 || // Jcc
|
||||||
|
opcode == 0x80 ||
|
||||||
|
opcode == 0x83 ||
|
||||||
|
(opcode & 0xFD) == 0xA0 || // MOV
|
||||||
|
opcode == 0xA8 || // TEST
|
||||||
|
(opcode & 0xF8) == 0xB0 || // MOV
|
||||||
|
(opcode & 0xFE) == 0xC0 || // RCL
|
||||||
|
opcode == 0xC6 || // MOV
|
||||||
|
opcode == 0xCD || // INT
|
||||||
|
(opcode & 0xFE) == 0xD4 || // AAD/AAM
|
||||||
|
(opcode & 0xF8) == 0xE0 || // LOOP/JCXZ
|
||||||
|
opcode == 0xEB ||
|
||||||
|
opcode == 0xF6 && (modRM & 0x30) == 0x00) // TEST
|
||||||
|
{
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
bytecount++;
|
||||||
|
}
|
||||||
|
else if((opcode & 0xF7) == 0xC2) // RET
|
||||||
|
{
|
||||||
|
if (dest) {
|
||||||
|
*(unsigned short*)dest = *(unsigned short*)func;
|
||||||
|
dest += 2;
|
||||||
|
}
|
||||||
|
func += 2;
|
||||||
|
bytecount += 2;
|
||||||
|
}
|
||||||
|
else if((opcode & 0xFC) == 0x80 ||
|
||||||
|
(opcode & 0xC7) == 0x05 ||
|
||||||
|
(opcode & 0xF8) == 0xB8 ||
|
||||||
|
(opcode & 0xFE) == 0xE8 || // CALL/Jcc
|
||||||
|
(opcode & 0xFE) == 0x68 ||
|
||||||
|
(opcode & 0xFC) == 0xA0 ||
|
||||||
|
(opcode & 0xEE) == 0xA8 ||
|
||||||
|
opcode == 0xC7 ||
|
||||||
|
opcode == 0xF7 && (modRM & 0x30) == 0x00)
|
||||||
|
{
|
||||||
|
if (dest) {
|
||||||
|
//Fix CALL/JMP offset
|
||||||
|
if ((opcode & 0xFE) == 0xE8) {
|
||||||
|
if (operandSize == 4)
|
||||||
|
*(long*)dest = ((func + *(long*)func) - dest);
|
||||||
|
else
|
||||||
|
*(short*)dest = ((func + *(short*)func) - dest);
|
||||||
|
} else {
|
||||||
|
if (operandSize == 4)
|
||||||
|
*(unsigned long*)dest = *(unsigned long*)func;
|
||||||
|
else
|
||||||
|
*(unsigned short*)dest = *(unsigned short*)func;
|
||||||
|
}
|
||||||
|
dest += operandSize;
|
||||||
|
}
|
||||||
|
func += operandSize;
|
||||||
|
bytecount += operandSize;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(opcode == 0xBA || // BT
|
||||||
|
opcode == 0x0F || // 3DNow!
|
||||||
|
(opcode & 0xFC) == 0x70 || // PSLLW
|
||||||
|
(opcode & 0xF7) == 0xA4 || // SHLD
|
||||||
|
opcode == 0xC2 ||
|
||||||
|
opcode == 0xC4 ||
|
||||||
|
opcode == 0xC5 ||
|
||||||
|
opcode == 0xC6)
|
||||||
|
{
|
||||||
|
if (dest)
|
||||||
|
*dest++ = *func++;
|
||||||
|
else
|
||||||
|
func++;
|
||||||
|
}
|
||||||
|
else if((opcode & 0xF0) == 0x80) // Jcc -i
|
||||||
|
{
|
||||||
|
if (dest) {
|
||||||
|
if (operandSize == 4)
|
||||||
|
*(unsigned long*)dest = *(unsigned long*)func;
|
||||||
|
else
|
||||||
|
*(unsigned short*)dest = *(unsigned short*)func;
|
||||||
|
|
||||||
|
dest += operandSize;
|
||||||
|
}
|
||||||
|
func += operandSize;
|
||||||
|
bytecount += operandSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytecount;
|
||||||
|
}
|
||||||
|
|
||||||
|
//insert a specific JMP instruction at the given location
|
||||||
|
void inject_jmp(void* src, void* dest) {
|
||||||
|
*(unsigned char*)src = OP_JMP;
|
||||||
|
*(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill a given block with NOPs
|
||||||
|
void fill_nop(void* src, unsigned int len) {
|
||||||
|
unsigned char* src2 = (unsigned char*)src;
|
||||||
|
while (len) {
|
||||||
|
*src2++ = OP_NOP;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* eval_jump(void* src) {
|
||||||
|
unsigned char* addr = (unsigned char*)src;
|
||||||
|
|
||||||
|
if (!addr) return 0;
|
||||||
|
|
||||||
|
//import table jump
|
||||||
|
if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) {
|
||||||
|
addr += 2;
|
||||||
|
addr = *(unsigned char**)addr;
|
||||||
|
//TODO: if addr points into the IAT
|
||||||
|
return *(void**)addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//8bit offset
|
||||||
|
else if (addr[0] == OP_JMP_BYTE) {
|
||||||
|
addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1];
|
||||||
|
//mangled 32bit jump?
|
||||||
|
if (addr[0] = OP_JMP) {
|
||||||
|
addr = addr + *(int*)&addr[1];
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
//32bit offset
|
||||||
|
else if (addr[0] == OP_JMP) {
|
||||||
|
addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
from ms detours package
|
||||||
|
static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION mbi;
|
||||||
|
VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
|
||||||
|
__try {
|
||||||
|
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
|
||||||
|
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
|
||||||
|
pDosHeader->e_lfanew);
|
||||||
|
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pbAddress >= ((PBYTE)pDosHeader +
|
||||||
|
pNtHeader->OptionalHeader
|
||||||
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
|
||||||
|
pbAddress < ((PBYTE)pDosHeader +
|
||||||
|
pNtHeader->OptionalHeader
|
||||||
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
|
||||||
|
pNtHeader->OptionalHeader
|
||||||
|
.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
38
extensions/tf2/asm/asm.h
Normal file
38
extensions/tf2/asm/asm.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef __ASM_H__
|
||||||
|
#define __ASM_H__
|
||||||
|
|
||||||
|
#define OP_JMP 0xE9
|
||||||
|
#define OP_JMP_SIZE 5
|
||||||
|
|
||||||
|
#define OP_NOP 0x90
|
||||||
|
#define OP_NOP_SIZE 1
|
||||||
|
|
||||||
|
#define OP_PREFIX 0xFF
|
||||||
|
#define OP_JMP_SEG 0x25
|
||||||
|
|
||||||
|
#define OP_JMP_BYTE 0xEB
|
||||||
|
#define OP_JMP_BYTE_SIZE 2
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//if dest is NULL, returns minimum number of bytes needed to be copied
|
||||||
|
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
|
||||||
|
//http://www.devmaster.net/forums/showthread.php?t=2311
|
||||||
|
int copy_bytes(unsigned char *func, unsigned char* dest, int required_len);
|
||||||
|
|
||||||
|
//insert a specific JMP instruction at the given location
|
||||||
|
void inject_jmp(void* src, void* dest);
|
||||||
|
|
||||||
|
//fill a given block with NOPs
|
||||||
|
void fill_nop(void* src, unsigned int len);
|
||||||
|
|
||||||
|
//evaluate a JMP at the target
|
||||||
|
void* eval_jump(void* src);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //__ASM_H__
|
@ -31,353 +31,46 @@
|
|||||||
|
|
||||||
#include "criticals.h"
|
#include "criticals.h"
|
||||||
|
|
||||||
ISourcePawnEngine *spengine = NULL;
|
|
||||||
CriticalHitManager g_CriticalHitManager;
|
|
||||||
IServerGameEnts *gameents = NULL;
|
IServerGameEnts *gameents = NULL;
|
||||||
|
|
||||||
int g_returnvalue;
|
CDetour *calcIsAttackCriticalDetour = NULL;
|
||||||
|
CDetour *calcIsAttackCriticalMeleeDetour = NULL;
|
||||||
|
CDetour *calcIsAttackCriticalKnifeDetour = NULL;
|
||||||
|
|
||||||
bool CriticalHitManager::CreateCriticalDetour()
|
IForward *g_critForward = NULL;
|
||||||
|
|
||||||
|
void InitialiseDetours()
|
||||||
{
|
{
|
||||||
if (!g_pGameConf->GetMemSig("CalcCritical", &critical_address) || !critical_address)
|
calcIsAttackCriticalDetour = CDetourManager::CreateDetour((void *)&TempDetour, 0, "CalcCritical");
|
||||||
|
calcIsAttackCriticalMeleeDetour = CDetourManager::CreateDetour((void *)&TempDetour, 0, "CalcCriticalMelee");
|
||||||
|
calcIsAttackCriticalKnifeDetour = CDetourManager::CreateDetour((void *)&TempDetour, 0, "CalcCriticalKnife");
|
||||||
|
|
||||||
|
bool HookCreated = false;
|
||||||
|
|
||||||
|
if (calcIsAttackCriticalDetour != NULL)
|
||||||
{
|
{
|
||||||
g_pSM->LogError(myself, "Could not locate CalcCritical - Disabling Critical Hit forward");
|
calcIsAttackCriticalDetour->EnableDetour();
|
||||||
return false;
|
HookCreated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_pGameConf->GetOffset("CalcCriticalBackup", (int *)&(critical_restore.bytes)))
|
if (calcIsAttackCriticalMeleeDetour != NULL)
|
||||||
{
|
{
|
||||||
g_pSM->LogError(myself, "Could not locate CalcCriticalBackup - Disabling Critical Hit forward");
|
calcIsAttackCriticalMeleeDetour->EnableDetour();
|
||||||
return false;
|
HookCreated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First, save restore bits */
|
if (calcIsAttackCriticalKnifeDetour != NULL)
|
||||||
for (size_t i=0; i<critical_restore.bytes; i++)
|
|
||||||
{
|
{
|
||||||
critical_restore.patch[i] = ((unsigned char *)critical_address)[i];
|
calcIsAttackCriticalKnifeDetour->EnableDetour();
|
||||||
|
HookCreated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
critical_callback = spengine->ExecAlloc(100);
|
if (!HookCreated)
|
||||||
JitWriter wr;
|
|
||||||
JitWriter *jit = ≀
|
|
||||||
wr.outbase = (jitcode_t)critical_callback;
|
|
||||||
wr.outptr = wr.outbase;
|
|
||||||
|
|
||||||
/* Function we are detouring into is
|
|
||||||
*
|
|
||||||
* void CriticalDetour(CTFWeaponBase(void *) *pWeapon)
|
|
||||||
*
|
|
||||||
* push pWeapon [ecx]
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
IA32_Push_Reg(jit, REG_ECX);
|
|
||||||
#elif defined PLATFORM_LINUX
|
|
||||||
IA32_Push_Rm_Disp8_ESP(jit, 4);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
|
||||||
IA32_Write_Jump32_Abs(jit, call, (void *)TempDetour);
|
|
||||||
|
|
||||||
|
|
||||||
#if defined PLATFORM_LINUX
|
|
||||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); //add esp, 4
|
|
||||||
#elif defined PLATFORM_WINDOWS
|
|
||||||
IA32_Pop_Reg(jit, REG_ECX);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//If TempDetour returns non-zero we want to load something into eax and return this value
|
|
||||||
|
|
||||||
//test eax, eax
|
|
||||||
IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG);
|
|
||||||
|
|
||||||
//jnz _skip
|
|
||||||
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
|
|
||||||
|
|
||||||
/* Patch old bytes in */
|
|
||||||
for (size_t i=0; i<critical_restore.bytes; i++)
|
|
||||||
{
|
{
|
||||||
jit->write_ubyte(critical_restore.patch[i]);
|
g_pSM->LogError(myself, "No critical hit forwards could be initialized - Disabled critical hit hooks");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return to the original function */
|
|
||||||
call = IA32_Jump_Imm32(jit, 0);
|
|
||||||
IA32_Write_Jump32_Abs(jit, call, (unsigned char *)critical_address + critical_restore.bytes);
|
|
||||||
|
|
||||||
//_skip:
|
|
||||||
//mov eax, [g_returnvalue]
|
|
||||||
//ret
|
|
||||||
IA32_Send_Jump8_Here(jit, jmp);
|
|
||||||
IA32_Mov_Eax_Mem(jit, (jit_int32_t)&g_returnvalue);
|
|
||||||
IA32_Return(jit);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CriticalHitManager::CreateCriticalMeleeDetour()
|
|
||||||
{
|
|
||||||
if (!g_pGameConf->GetMemSig("CalcCriticalMelee", &melee_address) || !melee_address)
|
|
||||||
{
|
|
||||||
g_pSM->LogError(myself, "Could not locate CalcCriticalMelee - Disabling Critical Hit forward");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_pGameConf->GetOffset("CalcCriticalMeleeBackup", (int *)&(melee_restore.bytes)))
|
|
||||||
{
|
|
||||||
g_pSM->LogError(myself, "Could not locate CalcCriticalMeleeBackup - Disabling Critical Hit forward");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* First, save restore bits */
|
|
||||||
for (size_t i=0; i<melee_restore.bytes; i++)
|
|
||||||
{
|
|
||||||
melee_restore.patch[i] = ((unsigned char *)melee_address)[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
melee_callback = spengine->ExecAlloc(100);
|
|
||||||
JitWriter wr;
|
|
||||||
JitWriter *jit = ≀
|
|
||||||
wr.outbase = (jitcode_t)melee_callback;
|
|
||||||
wr.outptr = wr.outbase;
|
|
||||||
|
|
||||||
/* Function we are detouring into is
|
|
||||||
*
|
|
||||||
* void CriticalDetour(CTFWeaponBase(void *) *pWeapon)
|
|
||||||
*
|
|
||||||
* push pWeapon [ecx]
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
IA32_Push_Reg(jit, REG_ECX);
|
|
||||||
#elif defined PLATFORM_LINUX
|
|
||||||
IA32_Push_Rm_Disp8_ESP(jit, 4);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
|
||||||
IA32_Write_Jump32_Abs(jit, call, (void *)TempDetour);
|
|
||||||
|
|
||||||
|
|
||||||
#if defined PLATFORM_LINUX
|
|
||||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); //add esp, 4
|
|
||||||
#elif defined PLATFORM_WINDOWS
|
|
||||||
IA32_Pop_Reg(jit, REG_ECX);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//If TempDetour returns non-zero we want to load something into eax and return this value
|
|
||||||
|
|
||||||
//test eax, eax
|
|
||||||
IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG);
|
|
||||||
|
|
||||||
//jnz _skip
|
|
||||||
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
|
|
||||||
|
|
||||||
int callbyte = -1;
|
|
||||||
/* The callbyte should return the nth byte (starting from 1) in the backup bytes - Should be an 0xE8 (call) */
|
|
||||||
g_pGameConf->GetOffset("CalcCriticalMeleeCallByte", &callbyte);
|
|
||||||
|
|
||||||
callbyte--;
|
|
||||||
void *function = NULL;
|
|
||||||
|
|
||||||
if (callbyte > -1)
|
|
||||||
{
|
|
||||||
/* Check if the 'callbyte' is actually a call */
|
|
||||||
if (melee_restore.patch[callbyte] != 0xE8)
|
|
||||||
{
|
|
||||||
g_pSM->LogError(myself, "Invalid callbyte - Melee detour may work incorrectly");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Find the absolute address of the function it calls */
|
|
||||||
void *offsetaddr = (void *)((unsigned char *)melee_address + callbyte + 1);
|
|
||||||
int offset = (int)*(unsigned char *)offsetaddr;
|
|
||||||
function = (unsigned char *)offsetaddr + offset + 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Patch old bytes in */
|
|
||||||
for (size_t i=0; i<melee_restore.bytes; i++)
|
|
||||||
{
|
|
||||||
if ((int)i != callbyte)
|
|
||||||
{
|
|
||||||
jit->write_ubyte(melee_restore.patch[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write in the adjusted call instead */
|
|
||||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
|
||||||
IA32_Write_Jump32_Abs(jit, call, function);
|
|
||||||
|
|
||||||
i += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return to the original function */
|
|
||||||
call = IA32_Jump_Imm32(jit, 0);
|
|
||||||
IA32_Write_Jump32_Abs(jit, call, (unsigned char *)melee_address + melee_restore.bytes);
|
|
||||||
|
|
||||||
//_skip:
|
|
||||||
//mov eax, [g_returnvalue]
|
|
||||||
//ret
|
|
||||||
IA32_Send_Jump8_Here(jit, jmp);
|
|
||||||
IA32_Mov_Eax_Mem(jit, (jit_int32_t)&g_returnvalue);
|
|
||||||
IA32_Return(jit);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CriticalHitManager::CreateCriticalKnifeDetour()
|
|
||||||
{
|
|
||||||
if (!g_pGameConf->GetMemSig("CalcCriticalKnife", &knife_address) || !knife_address)
|
|
||||||
{
|
|
||||||
g_pSM->LogError(myself, "Could not locate CalcCriticalKnife - Disabling Critical Hit forward");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_pGameConf->GetOffset("CalcCriticalKnifeBackup", (int *)&(knife_restore.bytes)))
|
|
||||||
{
|
|
||||||
g_pSM->LogError(myself, "Could not locate CalcCriticalKnifeBackup - Disabling Critical Hit forward");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* First, save restore bits */
|
|
||||||
for (size_t i=0; i<knife_restore.bytes; i++)
|
|
||||||
{
|
|
||||||
knife_restore.patch[i] = ((unsigned char *)knife_address)[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
knife_callback = spengine->ExecAlloc(100);
|
|
||||||
JitWriter wr;
|
|
||||||
JitWriter *jit = ≀
|
|
||||||
wr.outbase = (jitcode_t)knife_callback;
|
|
||||||
wr.outptr = wr.outbase;
|
|
||||||
|
|
||||||
/* Function we are detouring into is
|
|
||||||
*
|
|
||||||
* void CriticalDetour(CTFWeaponBase(void *) *pWeapon)
|
|
||||||
*
|
|
||||||
* push pWeapon [ecx]
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
IA32_Push_Reg(jit, REG_ECX);
|
|
||||||
#elif defined PLATFORM_LINUX
|
|
||||||
IA32_Push_Rm_Disp8_ESP(jit, 4);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
|
||||||
IA32_Write_Jump32_Abs(jit, call, (void *)TempDetour);
|
|
||||||
|
|
||||||
|
|
||||||
#if defined PLATFORM_LINUX
|
|
||||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); //add esp, 4
|
|
||||||
#elif defined PLATFORM_WINDOWS
|
|
||||||
IA32_Pop_Reg(jit, REG_ECX);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//If TempDetour returns non-zero we want to load something into eax and return this value
|
|
||||||
|
|
||||||
//test eax, eax
|
|
||||||
IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG);
|
|
||||||
|
|
||||||
//jnz _skip
|
|
||||||
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_NZ, 0);
|
|
||||||
|
|
||||||
/* Patch old bytes in */
|
|
||||||
for (size_t i=0; i<knife_restore.bytes; i++)
|
|
||||||
{
|
|
||||||
jit->write_ubyte(knife_restore.patch[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return to the original function */
|
|
||||||
call = IA32_Jump_Imm32(jit, 0);
|
|
||||||
IA32_Write_Jump32_Abs(jit, call, (unsigned char *)knife_address + knife_restore.bytes);
|
|
||||||
|
|
||||||
//_skip:
|
|
||||||
//mov eax, [g_returnvalue]
|
|
||||||
//ret
|
|
||||||
IA32_Send_Jump8_Here(jit, jmp);
|
|
||||||
IA32_Mov_Eax_Mem(jit, (jit_int32_t)&g_returnvalue);
|
|
||||||
IA32_Return(jit);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CriticalHitManager::EnableCriticalDetour()
|
|
||||||
{
|
|
||||||
if (!detoured)
|
|
||||||
{
|
|
||||||
if (normalcreated)
|
|
||||||
{
|
|
||||||
DoGatePatch((unsigned char *)critical_address, &critical_callback);
|
|
||||||
}
|
|
||||||
if (meleecreated)
|
|
||||||
{
|
|
||||||
DoGatePatch((unsigned char *)melee_address, &melee_callback);
|
|
||||||
}
|
|
||||||
if (knifecreated)
|
|
||||||
{
|
|
||||||
DoGatePatch((unsigned char *)knife_address, &knife_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
detoured = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CriticalHitManager::DeleteCriticalDetour()
|
|
||||||
{
|
|
||||||
if (detoured)
|
|
||||||
{
|
|
||||||
DisableCriticalDetour();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (critical_callback)
|
|
||||||
{
|
|
||||||
/* Free the gate */
|
|
||||||
spengine->ExecFree(critical_callback);
|
|
||||||
critical_callback = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (melee_callback)
|
|
||||||
{
|
|
||||||
/* Free the gate */
|
|
||||||
spengine->ExecFree(melee_callback);
|
|
||||||
melee_callback = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (knife_callback)
|
|
||||||
{
|
|
||||||
/* Free the gate */
|
|
||||||
spengine->ExecFree(knife_callback);
|
|
||||||
knife_callback = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TempDetour(void *pWeapon)
|
|
||||||
{
|
|
||||||
return g_CriticalHitManager.CriticalDetour(pWeapon);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CriticalHitManager::DisableCriticalDetour()
|
|
||||||
{
|
|
||||||
if (critical_callback)
|
|
||||||
{
|
|
||||||
/* Remove the patch */
|
|
||||||
ApplyPatch(critical_address, 0, &critical_restore, NULL);
|
|
||||||
detoured = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (melee_callback)
|
|
||||||
{
|
|
||||||
/* Remove the patch */
|
|
||||||
ApplyPatch(melee_address, 0, &melee_restore, NULL);
|
|
||||||
detoured = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (knife_callback)
|
|
||||||
{
|
|
||||||
/* Remove the patch */
|
|
||||||
ApplyPatch(knife_address, 0, &knife_restore, NULL);
|
|
||||||
detoured = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CheckBaseHandle(CBaseHandle &hndl)
|
int CheckBaseHandle(CBaseHandle &hndl)
|
||||||
@ -413,7 +106,7 @@ int CheckBaseHandle(CBaseHandle &hndl)
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CriticalHitManager::CriticalDetour(void *pWeapon)
|
DetourReturn TempDetour(void *pWeapon)
|
||||||
{
|
{
|
||||||
edict_t *pEdict = gameents->BaseEntityToEdict((CBaseEntity *)pWeapon);
|
edict_t *pEdict = gameents->BaseEntityToEdict((CBaseEntity *)pWeapon);
|
||||||
|
|
||||||
@ -431,23 +124,40 @@ bool CriticalHitManager::CriticalDetour(void *pWeapon)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!forward)
|
if (!g_critForward)
|
||||||
{
|
{
|
||||||
g_pSM->LogMessage(myself, "Invalid Forward");
|
g_pSM->LogMessage(myself, "Invalid Forward");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int returnValue=0;
|
||||||
|
|
||||||
CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pWeapon + info.actual_offset);
|
CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pWeapon + info.actual_offset);
|
||||||
int index = CheckBaseHandle(hndl);
|
int index = CheckBaseHandle(hndl);
|
||||||
|
|
||||||
forward->PushCell(index); //Client index
|
g_critForward->PushCell(index); //Client index
|
||||||
forward->PushCell(engine->IndexOfEdict(pEdict)); // Weapon index
|
g_critForward->PushCell(engine->IndexOfEdict(pEdict)); // Weapon index
|
||||||
forward->PushString(pEdict->GetClassName()); //Weapon classname
|
g_critForward->PushString(pEdict->GetClassName()); //Weapon classname
|
||||||
forward->PushCellByRef(&g_returnvalue); //return value
|
g_critForward->PushCellByRef(&returnValue); //return value
|
||||||
|
|
||||||
cell_t result = 0;
|
cell_t result = 0;
|
||||||
|
|
||||||
forward->Execute(&result);
|
g_critForward->Execute(&result);
|
||||||
|
|
||||||
return !!result;
|
if (result)
|
||||||
|
{
|
||||||
|
RETURN_DETOUR_VALUE(DETOUR_RESULT_OVERRIDE, returnValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RETURN_DETOUR_VALUE(DETOUR_RESULT_IGNORED, returnValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveDetours()
|
||||||
|
{
|
||||||
|
CDetourManager::DeleteDetour(calcIsAttackCriticalDetour);
|
||||||
|
CDetourManager::DeleteDetour(calcIsAttackCriticalMeleeDetour);
|
||||||
|
CDetourManager::DeleteDetour(calcIsAttackCriticalKnifeDetour);
|
||||||
}
|
}
|
||||||
|
@ -29,114 +29,21 @@
|
|||||||
* Version: $Id$
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_CRITICALS_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_CRITICALS_H_
|
||||||
|
|
||||||
#include "extension.h"
|
#include "extension.h"
|
||||||
#include <jit/jit_helpers.h>
|
#include <jit/jit_helpers.h>
|
||||||
#include <jit/x86/x86_macros.h>
|
#include <jit/x86/x86_macros.h>
|
||||||
#include "detours.h"
|
#include "CDetour/detours.h"
|
||||||
|
|
||||||
class CriticalHitManager
|
void InitialiseDetours();
|
||||||
{
|
void RemoveDetours();
|
||||||
public:
|
|
||||||
CriticalHitManager()
|
|
||||||
{
|
|
||||||
enabled = false;
|
|
||||||
detoured = false;
|
|
||||||
critical_address = NULL;
|
|
||||||
critical_callback = NULL;
|
|
||||||
|
|
||||||
melee_address = NULL;
|
|
||||||
melee_callback = NULL;
|
|
||||||
|
|
||||||
knife_address = NULL;
|
|
||||||
knife_callback = NULL;
|
|
||||||
|
|
||||||
forward = NULL;
|
|
||||||
|
|
||||||
normalcreated = false;
|
|
||||||
meleecreated = false;
|
|
||||||
knifecreated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
~CriticalHitManager()
|
|
||||||
{
|
|
||||||
if (forward != NULL)
|
|
||||||
{
|
|
||||||
forwards->ReleaseForward(forward);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeleteCriticalDetour();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Init()
|
|
||||||
{
|
|
||||||
normalcreated = CreateCriticalDetour();
|
|
||||||
meleecreated = CreateCriticalMeleeDetour();
|
|
||||||
knifecreated = CreateCriticalKnifeDetour();
|
|
||||||
|
|
||||||
if (!normalcreated && !meleecreated && !knifecreated)
|
|
||||||
{
|
|
||||||
enabled = false;
|
|
||||||
g_pSM->LogError(myself, "No critical hit forwards could be initialised - Disabled critical hit hooks");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
forward = forwards->CreateForward("TF2_CalcIsAttackCritical", ET_Hook, 4, NULL, Param_Cell, Param_Cell, Param_String, Param_CellByRef);
|
|
||||||
|
|
||||||
if (!forward)
|
|
||||||
{
|
|
||||||
g_pSM->LogError(myself, "Failed to create forward - Disabling critical hit hook");
|
|
||||||
enabled = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Only enable this once forwards exist. Requires IForwardListener functionality */
|
|
||||||
EnableCriticalDetour();
|
|
||||||
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsEnabled()
|
|
||||||
{
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CriticalDetour(void *pWeapon);
|
|
||||||
|
|
||||||
private:
|
|
||||||
IForward *forward;
|
|
||||||
|
|
||||||
/* These create/delete the allocated memory */
|
|
||||||
bool CreateCriticalDetour();
|
|
||||||
bool CreateCriticalMeleeDetour();
|
|
||||||
bool CreateCriticalKnifeDetour();
|
|
||||||
void DeleteCriticalDetour();
|
|
||||||
|
|
||||||
bool normalcreated;
|
|
||||||
bool meleecreated;
|
|
||||||
bool knifecreated;
|
|
||||||
|
|
||||||
/* These patch/unpatch the server.dll */
|
|
||||||
void EnableCriticalDetour();
|
|
||||||
void DisableCriticalDetour();
|
|
||||||
|
|
||||||
bool enabled;
|
|
||||||
bool detoured;
|
|
||||||
|
|
||||||
patch_t critical_restore;
|
|
||||||
void *critical_address;
|
|
||||||
void *critical_callback;
|
|
||||||
|
|
||||||
patch_t melee_restore;
|
|
||||||
void *melee_address;
|
|
||||||
void *melee_callback;
|
|
||||||
|
|
||||||
patch_t knife_restore;
|
|
||||||
void *knife_address;
|
|
||||||
void *knife_callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool TempDetour(void *pWeapon);
|
bool TempDetour(void *pWeapon);
|
||||||
|
|
||||||
extern ISourcePawnEngine *spengine;
|
extern IForward *g_critForward;
|
||||||
|
|
||||||
extern IServerGameEnts *gameents;
|
extern IServerGameEnts *gameents;
|
||||||
extern CriticalHitManager g_CriticalHitManager;
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_CRITICALS_H_
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "iplayerinfo.h"
|
#include "iplayerinfo.h"
|
||||||
#include "sm_trie_tpl.h"
|
#include "sm_trie_tpl.h"
|
||||||
#include "criticals.h"
|
#include "criticals.h"
|
||||||
|
#include "CDetour/detours.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file extension.cpp
|
* @file extension.cpp
|
||||||
@ -96,12 +97,14 @@ bool TF2Tools::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
|
||||||
|
|
||||||
sharesys->AddNatives(myself, g_TFNatives);
|
sharesys->AddNatives(myself, g_TFNatives);
|
||||||
sharesys->RegisterLibrary(myself, "tf2");
|
sharesys->RegisterLibrary(myself, "tf2");
|
||||||
|
|
||||||
playerhelpers->RegisterCommandTargetProcessor(this);
|
playerhelpers->RegisterCommandTargetProcessor(this);
|
||||||
|
|
||||||
spengine = g_pSM->GetScriptingEngine();
|
g_critForward = forwards->CreateForward("TF2_CalcIsAttackCritical", ET_Hook, 4, NULL, Param_Cell, Param_Cell, Param_String, Param_CellByRef);
|
||||||
|
|
||||||
g_pCVar = icvar;
|
g_pCVar = icvar;
|
||||||
|
|
||||||
@ -133,13 +136,17 @@ void TF2Tools::SDK_OnUnload()
|
|||||||
g_RegNatives.UnregisterAll();
|
g_RegNatives.UnregisterAll();
|
||||||
gameconfs->CloseGameConfigFile(g_pGameConf);
|
gameconfs->CloseGameConfigFile(g_pGameConf);
|
||||||
playerhelpers->UnregisterCommandTargetProcessor(this);
|
playerhelpers->UnregisterCommandTargetProcessor(this);
|
||||||
|
|
||||||
|
forwards->ReleaseForward(g_critForward);
|
||||||
|
|
||||||
|
RemoveDetours();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TF2Tools::SDK_OnAllLoaded()
|
void TF2Tools::SDK_OnAllLoaded()
|
||||||
{
|
{
|
||||||
SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
|
SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
|
||||||
|
|
||||||
g_CriticalHitManager.Init();
|
InitialiseDetours();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TF2Tools::RegisterConCommandBase(ConCommandBase *pVar)
|
bool TF2Tools::RegisterConCommandBase(ConCommandBase *pVar)
|
||||||
|
@ -215,10 +215,6 @@
|
|||||||
RelativePath="..\criticals.h"
|
RelativePath="..\criticals.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\detours.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\extension.h"
|
RelativePath="..\extension.h"
|
||||||
>
|
>
|
||||||
@ -259,6 +255,34 @@
|
|||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="CDetour"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\public\CBaseServer and friends\CDetour\detourhelpers.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\public\CBaseServer and friends\CDetour\detours.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\public\CBaseServer and friends\CDetour\detours.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="asm"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\asm\asm.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\asm\asm.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
</Files>
|
</Files>
|
||||||
<Globals>
|
<Globals>
|
||||||
</Globals>
|
</Globals>
|
||||||
|
@ -214,10 +214,6 @@
|
|||||||
RelativePath="..\criticals.h"
|
RelativePath="..\criticals.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\detours.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\extension.h"
|
RelativePath="..\extension.h"
|
||||||
>
|
>
|
||||||
@ -258,6 +254,34 @@
|
|||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="CDetour"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\public\CBaseServer and friends\CDetour\detourhelpers.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\public\CBaseServer and friends\CDetour\detours.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\public\CBaseServer and friends\CDetour\detours.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="asm"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\asm\asm.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\asm\asm.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
</Files>
|
</Files>
|
||||||
<Globals>
|
<Globals>
|
||||||
</Globals>
|
</Globals>
|
||||||
|
@ -6,37 +6,37 @@
|
|||||||
{
|
{
|
||||||
"Burn"
|
"Burn"
|
||||||
{
|
{
|
||||||
"library" "server"
|
"library" "server"
|
||||||
"windows" "\x56\x8B\xF1\x8B\x8E\x2A\x2A\x00\x00\x8B\x01\x8B\x90\x2A\x2A\x00\x00\xFF\xD2\x84\xC0"
|
"windows" "\x56\x8B\xF1\x8B\x8E\x2A\x2A\x00\x00\x8B\x01\x8B\x90\x2A\x2A\x00\x00\xFF\xD2\x84\xC0"
|
||||||
"linux" "@_ZN15CTFPlayerShared4BurnEP9CTFPlayerP13CTFWeaponBase"
|
"linux" "@_ZN15CTFPlayerShared4BurnEP9CTFPlayerP13CTFWeaponBase"
|
||||||
}
|
}
|
||||||
"RemoveDisguise"
|
"RemoveDisguise"
|
||||||
{
|
{
|
||||||
"library" "server"
|
"library" "server"
|
||||||
"windows" "\x51\x56\x8B\xF1\x8B\x46\x2A\x57\x8D\x7E\x2A\x8D\x4C\x24\x08\x83\xE0\xF7"
|
"windows" "\x51\x56\x8B\xF1\x8B\x46\x2A\x57\x8D\x7E\x2A\x8D\x4C\x24\x08\x83\xE0\xF7"
|
||||||
"linux" "@_ZN15CTFPlayerShared14RemoveDisguiseEv"
|
"linux" "@_ZN15CTFPlayerShared14RemoveDisguiseEv"
|
||||||
}
|
}
|
||||||
"Disguise"
|
"Disguise"
|
||||||
{
|
{
|
||||||
"library" "server"
|
"library" "server"
|
||||||
"windows" "\x56\x8B\xF1\x8B\x8E\x2A\x2A\x00\x00\xE8\x2A\x2A\x2A\x2A\x8B\x8E\x2A\x2A\x00\x00\x8B\x89\x2A\x2A\x00\x00"
|
"windows" "\x56\x8B\xF1\x8B\x8E\x2A\x2A\x00\x00\xE8\x2A\x2A\x2A\x2A\x8B\x8E\x2A\x2A\x00\x00\x8B\x89\x2A\x2A\x00\x00"
|
||||||
"linux" "@_ZN15CTFPlayerShared8DisguiseEii"
|
"linux" "@_ZN15CTFPlayerShared8DisguiseEii"
|
||||||
}
|
}
|
||||||
"CalcCritical"
|
"CalcCritical"
|
||||||
{
|
{
|
||||||
"library" "server"
|
"library" "server"
|
||||||
"linux" "@_ZN13CTFWeaponBase26CalcIsAttackCriticalHelperEv"
|
"linux" "@_ZN13CTFWeaponBase26CalcIsAttackCriticalHelperEv"
|
||||||
"windows" "\x83\xEC\x08\x53\x56\x6A\x00"
|
"windows" "\x83\xEC\x08\x53\x56\x6A\x00"
|
||||||
}
|
}
|
||||||
"CalcCriticalMelee"
|
"CalcCriticalMelee"
|
||||||
{
|
{
|
||||||
"library" "server"
|
"library" "server"
|
||||||
"linux" "@_ZN18CTFWeaponBaseMelee26CalcIsAttackCriticalHelperEv"
|
"linux" "@_ZN18CTFWeaponBaseMelee26CalcIsAttackCriticalHelperEv"
|
||||||
"windows" "\x83\xEC\x08\x53\x57\x8B\xF9\xE8\x2A\x2A\x2A\x2A\x8B\xD8"
|
"windows" "\x83\xEC\x08\x53\x57\x8B\xF9\xE8\x2A\x2A\x2A\x2A\x8B\xD8"
|
||||||
}
|
}
|
||||||
"CalcCriticalKnife"
|
"CalcCriticalKnife"
|
||||||
{
|
{
|
||||||
"library" "server"
|
"library" "server"
|
||||||
"linux" "@_ZN8CTFKnife26CalcIsAttackCriticalHelperEv"
|
"linux" "@_ZN8CTFKnife26CalcIsAttackCriticalHelperEv"
|
||||||
"windows" "\x33\xC0\x83\xB9\x08\x13\x00\x00\x01\x0F\x94\xC0\xC3"
|
"windows" "\x33\xC0\x83\xB9\x08\x13\x00\x00\x01\x0F\x94\xC0\xC3"
|
||||||
}
|
}
|
||||||
@ -49,27 +49,6 @@
|
|||||||
"windows" "281"
|
"windows" "281"
|
||||||
"linux" "282"
|
"linux" "282"
|
||||||
}
|
}
|
||||||
"CalcCriticalBackup"
|
|
||||||
{
|
|
||||||
"linux" "7"
|
|
||||||
"windows" "7"
|
|
||||||
}
|
|
||||||
"CalcCriticalMeleeBackup"
|
|
||||||
{
|
|
||||||
"linux" "7"
|
|
||||||
"windows" "7"
|
|
||||||
}
|
|
||||||
/* The byte number (starting from 1) of the call (0xE8) byte or -1 if none */
|
|
||||||
"CalcCriticalMeleeCallByte"
|
|
||||||
{
|
|
||||||
"linux" "-1"
|
|
||||||
"windows" "-1"
|
|
||||||
}
|
|
||||||
"CalcCriticalKnifeBackup"
|
|
||||||
{
|
|
||||||
"linux" "11"
|
|
||||||
"windows" "9"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user