Last active
December 29, 2024 10:03
-
-
Save user-grinch/3164c2055fd93aee5c20576dea226a24 to your computer and use it in GitHub Desktop.
GTA III VC SA DirectX Hooking Class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "pch.h" | |
#include "d3dhook.h" | |
#include "kiero/kiero.h" | |
#include "kiero/minhook/MinHook.h" | |
#include "imgui/imgui_impl_dx9.h" | |
#include "imgui/imgui_impl_dx11.h" | |
#include "imgui/imgui_impl_win32.h" | |
#include "../include/fonts/fonts.h" | |
#include "../trainer.h" | |
#include "../pages/menu.h" | |
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); | |
bool D3dHook::GetMouseState() { | |
return mouseShown; | |
} | |
void D3dHook::SetMouseState(bool state) { | |
mouseShown = state; | |
} | |
LRESULT D3dHook::hkWndProc(const HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { | |
ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam); | |
if (ImGui::GetIO().WantTextInput) { | |
#ifdef GTASA | |
Call<0x53F1E0>(); // CPad::ClearKeyboardHistory | |
#endif | |
return 1; | |
} | |
return CallWindowProc(oWndProc, hWnd, uMsg, wParam, lParam); | |
} | |
HRESULT D3dHook::hkReset(IDirect3DDevice9* pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters) { | |
ImGui_ImplDX9_InvalidateDeviceObjects(); | |
return oReset(pDevice, pPresentationParameters); | |
} | |
BOOL CALLBACK D3dHook::hkSetCursorPos(int x, int y) { | |
if (ImGui::GetIO().MouseDrawCursor) { | |
return true; | |
} | |
return oSetCursorPos(x, y); | |
} | |
BOOL CALLBACK D3dHook::hkShowCursor(bool flag) { | |
if (ImGui::GetIO().MouseDrawCursor) { | |
return oShowCursor(TRUE); | |
} | |
return oShowCursor(flag); | |
} | |
void D3dHook::ProcessFrame(void* ptr) { | |
ImGuiIO& io = ImGui::GetIO(); | |
static bool init; | |
if (init) { | |
ProcessMouse(); | |
ImGui_ImplWin32_NewFrame(); | |
if (gRenderer == eRenderer::Dx9) { | |
ImGui_ImplDX9_NewFrame(); | |
} else { | |
ImGui_ImplDX11_NewFrame(); | |
} | |
// Scale the menu if game resolution changed | |
static ImVec2 fScreenSize = ImVec2(-1, -1); | |
ImVec2 screen(screen::GetScreenWidth(), screen::GetScreenHeight()); | |
if (fScreenSize.x != screen.x && fScreenSize.y != screen.y) { | |
FontMgr::SetFontReloadRequired(true); | |
if (fScreenSize.x != -1 && fScreenSize.y != -1) { | |
Trainer.ResetParams(); | |
} | |
ImGuiStyle* style = &ImGui::GetStyle(); | |
float scaleX = screen.x / 1920.0f; | |
float scaleY = screen.y / 1080.0f; | |
style->FramePadding = ImVec2(5.0f * scaleX, 5.0f * scaleY); | |
style->ItemSpacing = ImVec2(5 * scaleX, 3 * scaleY); | |
style->ScrollbarSize = 15 * scaleX; | |
style->IndentSpacing = 8 * scaleX; | |
style->ItemInnerSpacing = ImVec2(2 * scaleX, 2 * scaleY); | |
fScreenSize = screen; | |
} | |
ImGui::NewFrame(); | |
if (pCallbackFunc != nullptr) { | |
pCallbackFunc(); | |
} | |
if (gRenderer == eRenderer::Dx9 && mouseShown) { | |
auto drawList = ImGui::GetForegroundDrawList(); | |
ImVec2 pos = ImGui::GetCurrentContext()->MouseLastValidPos; | |
float scaleX = screen::GetScreenWidth() / 1366.0f; | |
float scaleY = screen::GetScreenHeight() / 768.0f; | |
drawList->AddImage(gTextureList.FindTextureByName("cursor"), pos, pos + ImVec2(20.0f * scaleX, 20.0f * scaleY), {0, 0}, {1, 1}); | |
} else { | |
io.MouseDrawCursor = mouseShown; | |
} | |
ImGui::EndFrame(); | |
ImGui::Render(); | |
if (gRenderer == eRenderer::Dx9) { | |
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData()); | |
} else { | |
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); | |
} | |
if (FontMgr::IsFontReloadRequired()) | |
{ | |
if (gRenderer == eRenderer::Dx9) | |
{ | |
ImGui_ImplDX9_InvalidateDeviceObjects(); | |
} | |
else | |
{ | |
ImGui_ImplDX11_InvalidateDeviceObjects(); | |
} | |
FontMgr::ReloadAll(); | |
} | |
} else { | |
init = true; | |
ImGui_ImplWin32_Init(RsGlobal.ps->window); | |
#ifdef GTASA | |
patch::Nop(0x00531155, 5); // shift trigger fix | |
#endif | |
if (gRenderer == eRenderer::Dx9) { | |
gD3dDevice = ptr; | |
ImGui_ImplDX9_Init(reinterpret_cast<IDirect3DDevice9*>(ptr)); | |
} else { | |
// for dx11 device ptr is swapchain | |
reinterpret_cast<IDXGISwapChain*>(ptr)->GetDevice(__uuidof(ID3D11Device), &ptr); | |
gD3dDevice = ptr; | |
ID3D11DeviceContext* context; | |
reinterpret_cast<ID3D11Device*>(ptr)->GetImmediateContext(&context); | |
ImGui_ImplDX11_Init(reinterpret_cast<ID3D11Device*>(ptr), context); | |
} | |
ImGui_ImplWin32_EnableDpiAwareness(); | |
io.DisplaySize = {screen::GetScreenWidth(), screen::GetScreenHeight()}; | |
// Loading fonts | |
io.FontDefault = FontMgr::LoadFont("text", textFont, 16.5f); | |
FontMgr::LoadFont("title", titleFont, 21.0f); | |
FontMgr::LoadFont("icon", iconFont, 26.0f, true); | |
io.IniFilename = nullptr; | |
io.LogFilename = nullptr; | |
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; | |
oWndProc = (WNDPROC)SetWindowLongPtr(RsGlobal.ps->window, GWL_WNDPROC, (LRESULT)hkWndProc); | |
} | |
} | |
HRESULT D3dHook::hkEndScene(IDirect3DDevice9* pDevice) { | |
ProcessFrame(pDevice); | |
return oEndScene(pDevice); | |
} | |
HRESULT D3dHook::hkPresent(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) { | |
ProcessFrame(pSwapChain); | |
return oPresent(pSwapChain, SyncInterval, Flags); | |
} | |
void D3dHook::ProcessMouse() { | |
// Disable player controls for controllers | |
bool bMouseDisabled = false; | |
bool isController = patch::Get<BYTE>(BY_GAME(0xBA6818, 0x86968B, 0x5F03D8)); | |
#ifdef GTA3 | |
isController = !isController; | |
#endif | |
if ((isController || menuPage.m_bLockGameInputs) && (mouseShown || bMouseDisabled)) { | |
#ifdef GTASA | |
CPlayerPed *player = FindPlayerPed(); | |
CPad *pad = player ? player->GetPadFromPlayer() : NULL; | |
#else | |
CPad *pad = CPad::GetPad(0); | |
#endif | |
if (pad) { | |
if (mouseShown) { | |
bMouseDisabled = true; | |
#ifdef GTA3 | |
pad->DisablePlayerControls = true; | |
#else | |
pad->DisablePlayerControls = true; | |
#endif | |
} else { | |
bMouseDisabled = false; | |
#ifdef GTA3 | |
pad->DisablePlayerControls = false; | |
#else | |
pad->DisablePlayerControls = false; | |
#endif | |
} | |
} | |
} | |
static bool mouseState = false; | |
if (mouseState != mouseShown) { | |
if (mouseShown) { | |
patch::SetUChar(BY_GAME(0x6194A0, 0x6020A0, 0x580D20), 0xC3); // psSetMousePos | |
patch::Nop(BY_GAME(0x541DD7, 0x4AB6CA, 0x49272F), 5); // don't call CPad::UpdateMouse() | |
// patch::SetUChar(BY_GAME(0x541DD0, 0x4AB6C0, 0x492720), 0xC3); | |
#ifdef GTASA | |
// Fix bug with radio switching | |
patch::SetUChar(0x4EB731, 0xEB); // jz -> jmp, skip mouse checks | |
patch::SetUChar(0x4EB75A, 0xEB); // jz -> jmp, skip mouse checks | |
#endif | |
} else { | |
patch::SetUChar(BY_GAME(0x6194A0, 0x6020A0, 0x580D20), BY_GAME(0xE9, 0x53, 0x53)); | |
// patch::SetUChar(BY_GAME(0x541DD0, 0x4AB6C0, 0x492720), BY_GAME(0x56, 0xB9, 0x53)); | |
#ifdef GTASA | |
patch::SetRaw(0x541DD7, (char*)"\xE8\xE4\xD5\xFF\xFF", 5); | |
patch::SetUChar(0x4EB731, 0x74); // jz | |
patch::SetUChar(0x4EB75A, 0x74); // jz | |
#elif GTAVC | |
patch::SetRaw(0x4AB6CA, (char*)"\xE8\x51\x21\x00\x00", 5); | |
#else | |
patch::SetRaw(0x49272F, (char*)"\xE8\x6C\xF5\xFF\xFF", 5); | |
#endif | |
} | |
// Need to update pads before resting values | |
CPad::UpdatePads(); | |
CPad::NewMouseControllerState.x = 0; | |
CPad::NewMouseControllerState.y = 0; | |
#ifdef GTA3 | |
CPad::GetPad(0)->ClearMouseHistory(); | |
#else | |
CPad::ClearMouseHistory(); | |
CPad::GetPad(0)->NewState.DPadUp = 0; | |
CPad::GetPad(0)->OldState.DPadUp = 0; | |
CPad::GetPad(0)->NewState.DPadDown = 0; | |
CPad::GetPad(0)->OldState.DPadDown = 0; | |
#endif | |
mouseState = mouseShown; | |
} | |
} | |
bool D3dHook::Init(std::function<void()> pCallback) { | |
static bool hookInjected; | |
if (hookInjected) { | |
return false; | |
} | |
MH_Initialize(); | |
PVOID pSetCursorPos = GetProcAddress(GetModuleHandle("user32.dll"), "SetCursorPos"); | |
PVOID pShowCursor = GetProcAddress(GetModuleHandle("user32.dll"), "ShowCursor"); | |
MH_CreateHook(pSetCursorPos, hkSetCursorPos, reinterpret_cast<LPVOID*>(&oSetCursorPos)); | |
// MH_CreateHook(pShowCursor, hkShowCursor, reinterpret_cast<LPVOID*>(&oShowCursor)); | |
MH_EnableHook(pSetCursorPos); | |
// MH_EnableHook(pShowCursor); | |
/* | |
Must check for d3d9 first! | |
Seems to crash with nvidia geforce experience overlay | |
if anything else is checked before d3d9 | |
*/ | |
if (init(kiero::RenderType::D3D9) == kiero::Status::Success) { | |
gRenderer = eRenderer::Dx9; | |
// gD3dDevice = *reinterpret_cast<void**>(kiero::getMethodsTable()); | |
kiero::bind(16, (void**)&oReset, hkReset); | |
kiero::bind(42, (void**)&oEndScene, hkEndScene); | |
pCallbackFunc = pCallback; | |
hookInjected = true; | |
} else { | |
if (init(kiero::RenderType::D3D11) == kiero::Status::Success) { | |
gRenderer = eRenderer::Dx11; | |
kiero::bind(8, (void**)&oPresent, hkPresent); | |
pCallbackFunc = pCallback; | |
hookInjected = true; | |
} | |
} | |
return hookInjected; | |
} | |
void D3dHook::Shutdown() { | |
pCallbackFunc = nullptr; | |
SetWindowLongPtr(RsGlobal.ps->window, GWL_WNDPROC, (LRESULT)oWndProc); | |
if (gRenderer == eRenderer::Dx9) { | |
ImGui_ImplDX9_Shutdown(); | |
} else { | |
ImGui_ImplDX11_Shutdown(); | |
} | |
ImGui_ImplWin32_Shutdown(); | |
ImGui::DestroyContext(); | |
kiero::shutdown(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "pch.h" | |
/* | |
* DirectX Hooking Class | |
* Supports DX9 & DX11 | |
*/ | |
class D3dHook { | |
private: | |
using f_EndScene = HRESULT(CALLBACK*)(IDirect3DDevice9*); | |
using f_Present = HRESULT(CALLBACK*)(IDXGISwapChain*, UINT, UINT); | |
using f_Reset = HRESULT(CALLBACK*)(IDirect3DDevice9*, D3DPRESENT_PARAMETERS*); | |
using f_SetCursorPos = BOOL(CALLBACK*)(int, int); | |
using f_ShowCursor = BOOL(CALLBACK*)(bool); | |
static inline WNDPROC oWndProc; | |
static inline f_Present oPresent; | |
static inline f_EndScene oEndScene; | |
static inline f_SetCursorPos oSetCursorPos; | |
static inline f_ShowCursor oShowCursor; | |
static inline f_Reset oReset; | |
static inline bool mouseShown; | |
static inline std::function<void()> pCallbackFunc = nullptr; | |
static void CALLBACK ProcessFrame(void* ptr); | |
static LRESULT CALLBACK hkWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); | |
static void ProcessMouse(); | |
static BOOL CALLBACK hkSetCursorPos(int, int); | |
static BOOL CALLBACK hkShowCursor(bool); | |
// DirectX9 | |
static HRESULT CALLBACK hkEndScene(IDirect3DDevice9* pDevice); | |
static HRESULT CALLBACK hkReset(IDirect3DDevice9* pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters); | |
// DirectX11, Renderhook | |
static HRESULT CALLBACK hkPresent(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags); | |
public: | |
D3dHook() = delete; | |
D3dHook(D3dHook const&) = delete; | |
void operator=(D3dHook const&) = delete; | |
// Returns the current mouse visibility state | |
static bool GetMouseState(); | |
// Injects game hooks & stuff | |
static bool Init(std::function<void()> pCallback); | |
// Sets the current mouse visibility state | |
static void SetMouseState(bool state); | |
// Cleans up hooks | |
static void Shutdown(); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment