#include "CharacterUnmanaged.h"
#include <detours.h>
using namespace NosSmoothCore;
const BYTE WALK_OBJECT_PATTERN[] = { 0x33, 0xC9, 0x8B, 0x55, 0xFC, 0xA1, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00 };
const BYTE WALK_FUNCTION_PATTERN[] = { 0x55, 0x8B, 0xEC, 0x83, 0xC4, 0xEC, 0x53, 0x56, 0x57, 0x66, 0x89, 0x4D, 0xFA };
LPCSTR WALK_OBJECT_MASK = "xxxxxx????x????";
LPCSTR WALK_FUNCTION_MASK = "xxxxxxxxxxxxx";
void CharacterWalkDetourIn()
{
DWORD position = 0;
__asm
{
pushad
pushfd
mov position, edx
}
bool isAccepted = CharacterUnmanaged::GetInstance()->ExecuteWalkCallback(position);
__asm
{
popfd
popad
}
if (isAccepted) {
CharacterUnmanaged::GetInstance()->Walk(position);
}
}
// Detour entrypoint
// declspec naked to not mess up the stack
void __declspec(naked) CharacterWalkDetour()
{
unsigned int returnPush;
__asm {
pop eax
pop ebx
mov returnPush, eax // we have to push this value on the stack before returning
}
CharacterWalkDetourIn();
__asm {
push returnPush
ret
}
}
CharacterUnmanaged::CharacterUnmanaged()
{
}
void CharacterUnmanaged::Setup(ModuleHook moduleHook)
{
auto walkFunction = moduleHook.FindPattern(WALK_FUNCTION_PATTERN, WALK_FUNCTION_MASK);
auto walkObject = *(unsigned int*)(moduleHook.FindPattern(WALK_OBJECT_PATTERN, WALK_OBJECT_MASK) + 0x6);
if (walkFunction == 0)
{
throw "Could not find walk function.";
}
if (walkObject == 0)
{
throw "Could not find player object.";
}
_walkFunctionAddress = walkFunction;
_characterObjectAddress = walkObject;
}
void CharacterUnmanaged::SetWalkCallback(NativeWalkCallback walkCallback)
{
_walkCallback = walkCallback;
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)_walkFunctionAddress, CharacterWalkDetour);
DetourTransactionCommit();
}
void CharacterUnmanaged::Walk(DWORD position)
{
unsigned int walkFunction = _walkFunctionAddress;
unsigned int characterObject = _characterObjectAddress;
__asm
{
push 1
xor ecx, ecx
mov edx, position
mov eax, dword ptr ds : [characterObject]
mov eax, dword ptr ds : [eax]
call walkFunction
}
}
void CharacterUnmanaged::ResetHooks()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)_walkFunctionAddress, CharacterWalkDetour);
DetourTransactionCommit();
}
bool CharacterUnmanaged::ExecuteWalkCallback(const DWORD position)
{
if (_walkCallback != nullptr) {
return _walkCallback(position);
}
return true;
}