From fcb1f599a46fb22212d28ac9e9e42dcacdc5ecd0 Mon Sep 17 00:00:00 2001 From: kedou Date: Fri, 7 Aug 2026 21:25:51 +0800 Subject: [PATCH] fix: restore esp transform fallback --- CFramework/Cheat/Aim.cpp | 2 +- CFramework/Cheat/SDK/CPlayer/CPlayer.cpp | 102 ++++++++++++++++-- CFramework/Cheat/SDK/CPlayer/CPlayer.h | 2 + CFramework/Cheat/SDK/GameSDK/Offset.h | 29 +++++ CFramework/Framework/Config/Config.h | 2 +- CFramework/Framework/Overlay/Overlay.cpp | 8 +- CFramework/Framework/Overlay/Overlay.h | 2 +- .../Overlay/OverlayUserFunctions.cpp | 7 +- CFramework/main.cpp | 9 +- 9 files changed, 145 insertions(+), 18 deletions(-) diff --git a/CFramework/Cheat/Aim.cpp b/CFramework/Cheat/Aim.cpp index c985038..119f724 100644 --- a/CFramework/Cheat/Aim.cpp +++ b/CFramework/Cheat/Aim.cpp @@ -258,7 +258,7 @@ Vector3 CFramework::GetAimBone(CPlayer* pEntity) switch (g.g_AimBone) { case 1: return pEntity->m_vecNeckOrigin; - case 2: return pEntity->m_vecOrigin; + case 2: return pEntity->GetBonePosition(BONE_SPINE_3); // Ribcage case 0: default: return pEntity->m_vecHeadOrigin; diff --git a/CFramework/Cheat/SDK/CPlayer/CPlayer.cpp b/CFramework/Cheat/SDK/CPlayer/CPlayer.cpp index 4506246..b13ee09 100644 --- a/CFramework/Cheat/SDK/CPlayer/CPlayer.cpp +++ b/CFramework/Cheat/SDK/CPlayer/CPlayer.cpp @@ -2,6 +2,42 @@ std::vector PlayerBoneList{ BONE_PELVIS, BONE_LEFT_THIGH, BONE_LEFT_FOOT, BONE_RIGHT_THIGH, BONE_RIGHT_FOOT, BONE_LEFT_FOREARM, BONE_LEFT_PALM, BONE_RIGHT_FOREARM, BONE_RIGHT_PALM }; +namespace +{ + uintptr_t ReadBifacialOriginal(uintptr_t playerBones, uintptr_t fieldOffset) + { + const uintptr_t bifacialTransform = m.Read(playerBones + fieldOffset); + return bifacialTransform + ? m.Read(bifacialTransform + offset::BifacialTransform::Original) + : 0; + } + + uintptr_t ReadTransformArrayElement(uintptr_t array, int index) + { + if (!array || index < 0 || index > 1) + return 0; + + return m.Read(array + offset::PlayerBones::TransformArrayData + static_cast(index) * sizeof(uintptr_t)); + } + + Vector3 ReadTransformPositionWithFallback(uintptr_t transform) + { + if (!transform) + return {}; + + Vector3 position = GetTransformPosition(transform); + if (!Vec3_Empty(position)) + return position; + + // Keep compatibility with the previous Transform wrapper layout. + uintptr_t wrappedTransform = m.Read(transform + 0x10); + if (!wrappedTransform || wrappedTransform == transform) + return {}; + + return GetTransformPosition(wrappedTransform); + } +} + bool CPlayer::Update() { m_vecOrigin = GetBonePosition(BONE_ORIGIN); @@ -15,6 +51,8 @@ void CPlayer::UpdateStatic() m_pProfile = 0; m_pInfo = 0; m_pSetting = 0; + m_pPlayerBody = 0; + m_pPlayerBones = 0; m_pWeaponAnimation = 0; m_iSpawnType = 0; m_pBoneArray = {}; @@ -27,6 +65,10 @@ void CPlayer::UpdateStatic() m_pHealthController = m.Read(m_address + offset::Player::pHealthController); m_pWeaponAnimation = m.Read(m_address + offset::Player::pWeaponAnimation); + m_pPlayerBody = m.Read(m_address + offset::Player::pPlayerBody); + if (m_pPlayerBody) + m_pPlayerBones = m.Read(m_pPlayerBody + offset::PlayerBody::PlayerBones); + m_pProfile = m.Read(m_address + offset::Player::pProfile); if (m_pProfile) { @@ -41,7 +83,7 @@ void CPlayer::UpdateStatic() // PlayerBody +0x30 = SkeletonRootJoint; Skeleton +0x30 = values List; // List +0x10 = Transform[] data pointer, as described by dump.txt. - const uintptr_t boneMatrix = m.ReadChain(m_address, { offset::Player::pPlayerBody, 0x30, 0x30, 0x10 }); + const uintptr_t boneMatrix = m.ReadChain(m_address, { offset::Player::pPlayerBody, offset::PlayerBody::SkeletonRootJoint, 0x30, 0x10 }); if (boneMatrix) m_pBoneArray = m.Read(boneMatrix + 0x20); } @@ -121,13 +163,61 @@ Vector3 CPlayer::GetBonePosition(const int BoneId) if (BoneId < 0 || BoneId >= kBoneCount) return {}; - const uintptr_t bone = m_pBoneArray.address[BoneId]; - if (!bone) - return {}; + uintptr_t transform = 0; + if (m_pPlayerBones) + { + switch (BoneId) + { + case BONE_ORIGIN: + transform = m.Read(m_pPlayerBones + offset::PlayerBones::RootJoint); + break; + case BONE_NECK: + transform = m.Read(m_pPlayerBones + offset::PlayerBones::Neck); + break; + case BONE_HEAD: + transform = ReadBifacialOriginal(m_pPlayerBones, offset::PlayerBones::Head); + break; + case BONE_PELVIS: + transform = ReadBifacialOriginal(m_pPlayerBones, offset::PlayerBones::Pelvis); + break; + case BONE_LEFT_THIGH: + transform = ReadBifacialOriginal(m_pPlayerBones, offset::PlayerBones::LeftThigh); + break; + case BONE_RIGHT_THIGH: + transform = ReadBifacialOriginal(m_pPlayerBones, offset::PlayerBones::RightThigh); + break; + case BONE_LEFT_FOREARM: + transform = ReadTransformArrayElement(m.Read(m_pPlayerBones + offset::PlayerBones::Forearms), 0); + break; + case BONE_RIGHT_FOREARM: + transform = ReadTransformArrayElement(m.Read(m_pPlayerBones + offset::PlayerBones::Forearms), 1); + break; + case BONE_LEFT_PALM: + transform = m.Read(m_pPlayerBones + offset::PlayerBones::LeftPalm); + break; + case BONE_RIGHT_PALM: + transform = m.Read(m_pPlayerBones + offset::PlayerBones::RightPalm); + break; + case BONE_SPINE_3: + transform = ReadBifacialOriginal(m_pPlayerBones, offset::PlayerBones::Ribcage); + break; + default: + break; + } + } - uintptr_t transform = m.Read(bone + 0x10); + // Feet and any unmapped legacy IDs fall back to the current Skeleton.values array. + // The array elements are Transform references; do not dereference +0x10 here. if (!transform) + transform = m_pBoneArray.address[BoneId]; + + const Vector3 position = ReadTransformPositionWithFallback(transform); + if (!Vec3_Empty(position)) + return position; + + const uintptr_t legacyTransform = m_pBoneArray.address[BoneId]; + if (!legacyTransform || legacyTransform == transform) return {}; - return GetTransformPosition(transform); + return ReadTransformPositionWithFallback(legacyTransform); } diff --git a/CFramework/Cheat/SDK/CPlayer/CPlayer.h b/CFramework/Cheat/SDK/CPlayer/CPlayer.h index a60eaff..23e23cb 100644 --- a/CFramework/Cheat/SDK/CPlayer/CPlayer.h +++ b/CFramework/Cheat/SDK/CPlayer/CPlayer.h @@ -13,6 +13,8 @@ public: uintptr_t m_pProfile{ 0 }; uintptr_t m_pInfo{ 0 }; uintptr_t m_pSetting{ 0 }; + uintptr_t m_pPlayerBody{ 0 }; + uintptr_t m_pPlayerBones{ 0 }; uintptr_t m_pHealthController{ 0 }; uintptr_t m_pWeaponAnimation{ 0 }; diff --git a/CFramework/Cheat/SDK/GameSDK/Offset.h b/CFramework/Cheat/SDK/GameSDK/Offset.h index 5d8c959..ecfd4d3 100644 --- a/CFramework/Cheat/SDK/GameSDK/Offset.h +++ b/CFramework/Cheat/SDK/GameSDK/Offset.h @@ -25,6 +25,35 @@ namespace offset constexpr auto pHealthController = 0x660; // _healthController } + // EFT.PlayerBody / EFT.PlayerBones (dump.txt) + namespace PlayerBody + { + constexpr auto PlayerBones = 0x28; + constexpr auto SkeletonRootJoint = 0x30; + } + + namespace PlayerBones + { + constexpr auto Neck = 0x48; + constexpr auto Forearms = 0x70; + constexpr auto LeftPalm = 0x78; + constexpr auto RightPalm = 0x80; + constexpr auto RootJoint = 0x90; + constexpr auto Ribcage = 0x110; + constexpr auto Head = 0x118; + constexpr auto Body = 0x140; + constexpr auto Pelvis = 0x150; + constexpr auto LeftThigh = 0x158; + constexpr auto RightThigh = 0x160; + constexpr auto Spine3 = 0x168; + constexpr auto TransformArrayData = 0x20; + } + + namespace BifacialTransform + { + constexpr auto Original = 0x10; + } + // EFT.MovementContext (dump.txt: EFT.MovementContext) namespace MovementContext { diff --git a/CFramework/Framework/Config/Config.h b/CFramework/Framework/Config/Config.h index af6762c..abc4714 100644 --- a/CFramework/Framework/Config/Config.h +++ b/CFramework/Framework/Config/Config.h @@ -39,7 +39,7 @@ struct Globals float g_AimSens = 1.0f; // Mouse 模式灵敏度倍率 float g_AimMaxSpeed = 80.f; // Mouse 模式单帧最大移动 [px] float g_AimMaxDist = 500.f; // 最大锁定距离 [m] - int g_AimBone = 0; // 0=Head 1=Neck 2=Body + int g_AimBone = 0; // 0=Head 1=Neck 2=Body (PlayerBones direct transforms) bool g_AimTargetPMC = true; bool g_AimTargetScav = true; bool g_AimTargetBoss = true; diff --git a/CFramework/Framework/Overlay/Overlay.cpp b/CFramework/Framework/Overlay/Overlay.cpp index fd309fc..3a5ca2a 100644 --- a/CFramework/Framework/Overlay/Overlay.cpp +++ b/CFramework/Framework/Overlay/Overlay.cpp @@ -24,7 +24,7 @@ bool Overlay::CreateOverlay() // Create Overlay wc = { sizeof(WNDCLASSEXA), 0, WndProc, 0, 0, NULL, NULL, NULL, NULL, Title, Class, NULL}; RegisterClassExA(&wc); - Hwnd = CreateWindowExA(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW | WS_EX_TOPMOST, wc.lpszClassName, wc.lpszMenuName, WS_POPUP | WS_VISIBLE, g.GamePoint.x, g.GamePoint.y, g.GameRect.right, g.GameRect.bottom, NULL, NULL, wc.hInstance, NULL); + Hwnd = CreateWindowExA(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE, wc.lpszClassName, wc.lpszMenuName, WS_POPUP | WS_VISIBLE, g.GamePoint.x, g.GamePoint.y, g.GameRect.right, g.GameRect.bottom, NULL, NULL, wc.hInstance, NULL); SetLayeredWindowAttributes(Hwnd, RGB(0, 0, 0), 255, LWA_ALPHA); MARGINS margin = { -1 }; DwmExtendFrameIntoClientArea(Hwnd, &margin); @@ -117,6 +117,12 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + // ESP overlay must never activate or consume the game's mouse input. + if (!g.ShowMenu && msg == WM_NCHITTEST) + return HTTRANSPARENT; + if (!g.ShowMenu && msg == WM_MOUSEACTIVATE) + return MA_NOACTIVATE; + if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) return true; diff --git a/CFramework/Framework/Overlay/Overlay.h b/CFramework/Framework/Overlay/Overlay.h index f955bea..6d52101 100644 --- a/CFramework/Framework/Overlay/Overlay.h +++ b/CFramework/Framework/Overlay/Overlay.h @@ -25,7 +25,7 @@ private: // Window LONG LONG MenuStyle = WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST; - LONG ESPStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST; + LONG ESPStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE; bool CreateOverlay(); HWND GetTargetWindow(const std::string processName); // 実行ファイル名からウィンドウハンドルを取得する diff --git a/CFramework/Framework/Overlay/OverlayUserFunctions.cpp b/CFramework/Framework/Overlay/OverlayUserFunctions.cpp index 6f94734..080afcd 100644 --- a/CFramework/Framework/Overlay/OverlayUserFunctions.cpp +++ b/CFramework/Framework/Overlay/OverlayUserFunctions.cpp @@ -12,6 +12,7 @@ bool Overlay::InitOverlay(const std::string targetName, int InitMode) } GetClassNameA(TargetHwnd, TargetClass, sizeof(TargetClass)); + g.GameHwnd = TargetHwnd; return CreateOverlay(); } @@ -68,9 +69,9 @@ void Overlay::OverlayManager() LONG TmpLong = GetWindowLong(Hwnd, GWL_EXSTYLE); if (g.ShowMenu && MenuStyle != TmpLong) - SetWindowLong(Hwnd, GWL_EXSTYLE, WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST); + SetWindowLong(Hwnd, GWL_EXSTYLE, MenuStyle); else if (!g.ShowMenu && ESPStyle != TmpLong) - SetWindowLong(Hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST); + SetWindowLong(Hwnd, GWL_EXSTYLE, ESPStyle); // MenuToggle if (GetKeyState(g.g_MenuKey) && !g.ShowMenu) { @@ -97,7 +98,7 @@ void Overlay::OverlayManager() { g.GameRect = TmpRect; g.GamePoint = TmpPoint; - SetWindowPos(Hwnd, nullptr, TmpPoint.x, TmpPoint.y, g.GameRect.right, g.GameRect.bottom, SWP_NOREDRAW); + SetWindowPos(Hwnd, nullptr, TmpPoint.x, TmpPoint.y, g.GameRect.right, g.GameRect.bottom, SWP_NOREDRAW | SWP_NOACTIVATE); } } diff --git a/CFramework/main.cpp b/CFramework/main.cpp index 1ad92d6..23b92f6 100644 --- a/CFramework/main.cpp +++ b/CFramework/main.cpp @@ -39,8 +39,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine { auto overlay = std::make_unique(); - // Fix DPI Scale - SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE); + // 使用每监视器 DPI,保证 overlay、GameRect 和 W2S 使用同一套物理像素坐标。 + SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); // ウィンドウをベースにして初期化を行う if (!m.AttachProcess("EscapeFromTarkov", InitMode::WINDOW_TITLE)) // 詳細は Memory/Memory.h を参照 @@ -50,8 +50,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine if (!overlay->InitOverlay("EscapeFromTarkov", InitMode::WINDOW_TITLE)) // MemoryInitModeと同様 return 2; - // 低级输入钩子 (GetAsyncKeyState 检测不到鼠标键的环境用) - InstallInputHook(); + // 不安装全局 WH_MOUSE_LL 钩子,避免改变游戏原始鼠标输入链路。 + // 鼠标按键使用 GetAsyncKeyState,F9 可作为触发键兜底。 // ImGui io setting ImGuiIO& io = ImGui::GetIO(); (void)io; @@ -92,7 +92,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine overlay->OverlayLoop(); overlay->DestroyOverlay(); - RemoveInputHook(); m.DetachProcess(); g.process_active = false;