fix: update offsets from dump
This commit is contained in:
parent
4dca333267
commit
52454e23ea
|
|
@ -365,8 +365,8 @@ void CFramework::ScanRotationOffset()
|
||||||
s_cands.clear();
|
s_cands.clear();
|
||||||
m_scanResult[0] = 0;
|
m_scanResult[0] = 0;
|
||||||
|
|
||||||
// Player 構造 [0x100, 0x700] 内の 8byte アライン済みポインタ
|
// Player 构造 [0x20, 0x700] 内的 8byte アライン済みポインタ
|
||||||
for (uintptr_t mcOff = 0x100; mcOff <= 0x700; mcOff += 0x8)
|
for (uintptr_t mcOff = 0x20; mcOff <= 0x700; mcOff += 0x8)
|
||||||
{
|
{
|
||||||
uintptr_t ptr = m.Read<uintptr_t>(local.m_address + mcOff);
|
uintptr_t ptr = m.Read<uintptr_t>(local.m_address + mcOff);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
|
|
@ -392,7 +392,7 @@ void CFramework::ScanRotationOffset()
|
||||||
|
|
||||||
if (s_cands.empty())
|
if (s_cands.empty())
|
||||||
{
|
{
|
||||||
strcpy_s(m_scanResult, "未找到候选,请扩大扫描范围 (0x100-0x700)");
|
strcpy_s(m_scanResult, "未找到候选,请扩大扫描范围 (0x20-0x700)");
|
||||||
m_scanPhase = 0;
|
m_scanPhase = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,9 @@ private:
|
||||||
}
|
}
|
||||||
void HealthBar(float x, float y, float w, float h, int value, int v_max)
|
void HealthBar(float x, float y, float w, float h, int value, int v_max)
|
||||||
{
|
{
|
||||||
|
if (v_max <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
RectFilled(x, y, x + w, y + h, ImColor(0.f, 0.f, 0.f, 0.725f), 0.f, 0);
|
RectFilled(x, y, x + w, y + h, ImColor(0.f, 0.f, 0.f, 0.725f), 0.f, 0);
|
||||||
RectFilled(x, y, x + w, y + ((h / float(v_max)) * (float)value), ImColor(min(510 * (v_max - value) / 100, 255), min(510 * value / 100, 255), 25, 255), 0.0f, 0);
|
RectFilled(x, y, x + w, y + ((h / float(v_max)) * (float)value), ImColor(min(510 * (v_max - value) / 100, 255), min(510 * value / 100, 255), 25, 255), 0.0f, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -234,11 +234,11 @@ void CFramework::RenderMenu()
|
||||||
ImGui::InputInt("MC", &g.g_AimMcOffset, 8, 8, ImGuiInputTextFlags_CharsHexadecimal);
|
ImGui::InputInt("MC", &g.g_AimMcOffset, 8, 8, ImGuiInputTextFlags_CharsHexadecimal);
|
||||||
ImGui::InputInt("旋转", &g.g_AimRotOffset, 4, 4, ImGuiInputTextFlags_CharsHexadecimal);
|
ImGui::InputInt("旋转", &g.g_AimRotOffset, 4, 4, ImGuiInputTextFlags_CharsHexadecimal);
|
||||||
|
|
||||||
// 误改输入框会直接导致 Memory 模式失效, 一键恢复本客户端实测默认值
|
// dump.txt: MovementContext = Player +0x58, Rotation_1 = MovementContext +0x27C
|
||||||
if (ImGui::Button("重置偏移 (0x1E0/0x3AC)", ImVec2(ImGui::GetContentRegionAvail().x, 0.f)))
|
if (ImGui::Button("重置偏移 (0x58/0x27C)", ImVec2(ImGui::GetContentRegionAvail().x, 0.f)))
|
||||||
{
|
{
|
||||||
g.g_AimMcOffset = 0x1E0;
|
g.g_AimMcOffset = 0x58;
|
||||||
g.g_AimRotOffset = 0x3AC;
|
g.g_AimRotOffset = 0x27C;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Button("扫描旋转偏移(两步)", ImVec2(ImGui::GetContentRegionAvail().x, 0.f)))
|
if (ImGui::Button("扫描旋转偏移(两步)", ImVec2(ImGui::GetContentRegionAvail().x, 0.f)))
|
||||||
|
|
|
||||||
|
|
@ -4,83 +4,130 @@ std::vector<int> PlayerBoneList{ BONE_PELVIS, BONE_LEFT_THIGH, BONE_LEFT_FOOT, B
|
||||||
|
|
||||||
bool CPlayer::Update()
|
bool CPlayer::Update()
|
||||||
{
|
{
|
||||||
// Position
|
m_vecOrigin = GetBonePosition(BONE_ORIGIN);
|
||||||
m_vecOrigin = GetBonePosition(BONE_ORIGIN);
|
|
||||||
|
|
||||||
if (Vec3_Empty(m_vecOrigin))
|
return !Vec3_Empty(m_vecOrigin);
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayer::UpdateStatic()
|
void CPlayer::UpdateStatic()
|
||||||
{
|
{
|
||||||
// Health
|
m_pHealthController = 0;
|
||||||
uintptr_t m_pHealthController = m.Read<uintptr_t>(m_address + offset::Player::pHealthController); // HealthController
|
m_pProfile = 0;
|
||||||
uintptr_t m_pHealthBody = m.Read<uintptr_t>(m_pHealthController + 0x68);
|
m_pInfo = 0;
|
||||||
m_pBodyController = m.Read<uintptr_t>(m_pHealthBody + 0x18);
|
m_pSetting = 0;
|
||||||
|
m_pWeaponAnimation = 0;
|
||||||
|
m_iSpawnType = 0;
|
||||||
|
m_pBoneArray = {};
|
||||||
|
m_vecBoneList.clear();
|
||||||
|
|
||||||
// Bone
|
if (!m_address)
|
||||||
uintptr_t boneMatrix = m.ReadChain(m_address, { offset::Player::pPlayerBody, 0x30, 0x30, 0x10 });
|
return;
|
||||||
m_pBoneArray = m.Read<CBoneArray>(boneMatrix + 0x20);
|
|
||||||
|
|
||||||
// Other pointer
|
// EFT.Player fields from dump.txt.
|
||||||
m_pProfile = m.Read<uintptr_t>(m_address + offset::Player::pProfile);
|
m_pHealthController = m.Read<uintptr_t>(m_address + offset::Player::pHealthController);
|
||||||
m_pInfo = m.Read<uintptr_t>(m_pProfile + 0x40);
|
m_pWeaponAnimation = m.Read<uintptr_t>(m_address + offset::Player::pWeaponAnimation);
|
||||||
m_pSetting = m.Read<uintptr_t>(m_pInfo + 0x50);
|
|
||||||
|
|
||||||
m.Read<uintptr_t>(m_address + offset::Player::pWeaponAnimation);
|
m_pProfile = m.Read<uintptr_t>(m_address + offset::Player::pProfile);
|
||||||
|
if (m_pProfile)
|
||||||
|
{
|
||||||
|
m_pInfo = m.Read<uintptr_t>(m_pProfile + offset::Profile::pInfoClass);
|
||||||
|
if (m_pInfo)
|
||||||
|
{
|
||||||
|
m_pSetting = m.Read<uintptr_t>(m_pInfo + offset::InfoClass::profileInfoSettingsClass);
|
||||||
|
if (m_pSetting)
|
||||||
|
m_iSpawnType = m.Read<int>(m_pSetting + 0x10); // ProfileInfoSettingsClass.Role
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Player data
|
// PlayerBody +0x30 = SkeletonRootJoint; Skeleton +0x30 = values List;
|
||||||
m_iSpawnType = m.Read<int>(m_pSetting + 0x10); // SpawnType
|
// List +0x10 = Transform[] data pointer, as described by dump.txt.
|
||||||
|
const uintptr_t boneMatrix = m.ReadChain(m_address, { offset::Player::pPlayerBody, 0x30, 0x30, 0x10 });
|
||||||
|
if (boneMatrix)
|
||||||
|
m_pBoneArray = m.Read<CBoneArray>(boneMatrix + 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayer::UpdateHealth()
|
void CPlayer::UpdateHealth()
|
||||||
{
|
{
|
||||||
float h{ 0 };
|
m_fHealth = 0.f;
|
||||||
float max{ 0 };
|
m_fHealthMax = 0.f;
|
||||||
|
|
||||||
for (int j = 0; j < 7; j++)
|
if (!m_address)
|
||||||
{
|
return;
|
||||||
uintptr_t body_part = m.Read<uintptr_t>(m_pBodyController + 0x30 + (j * 0x18));
|
|
||||||
uintptr_t health_container = m.Read<uintptr_t>(body_part + 0x10);
|
|
||||||
h += m.Read<float>(health_container + 0x10);
|
|
||||||
max += m.Read<float>(health_container + 0x14);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_fHealth = h;
|
const uintptr_t healthController = m_pHealthController != 0
|
||||||
m_fHealthMax = max;
|
? m_pHealthController
|
||||||
|
: m.Read<uintptr_t>(m_address + offset::Player::pHealthController);
|
||||||
|
if (!healthController)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// GClass3009<T>.Dictionary_0_1 contains BodyPartState<T> entries.
|
||||||
|
const uintptr_t bodyParts = m.Read<uintptr_t>(healthController + offset::HealthController::BodyParts);
|
||||||
|
if (!bodyParts)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const uintptr_t entries = m.Read<uintptr_t>(bodyParts + offset::HealthController::DictionaryEntries);
|
||||||
|
const int entryCount = m.Read<int>(bodyParts + offset::HealthController::DictionaryCount);
|
||||||
|
if (!entries || entryCount <= 0 || entryCount > 64)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < entryCount; ++i)
|
||||||
|
{
|
||||||
|
const uintptr_t entry = entries + offset::HealthController::ArrayData
|
||||||
|
+ static_cast<uintptr_t>(i) * offset::HealthController::EntryStride;
|
||||||
|
const uintptr_t bodyPartState = m.Read<uintptr_t>(entry + offset::HealthController::EntryValue);
|
||||||
|
if (!bodyPartState)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const uintptr_t healthValue = m.Read<uintptr_t>(bodyPartState + offset::HealthController::BodyPartHealth);
|
||||||
|
if (!healthValue)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_fHealth += m.Read<float>(healthValue + offset::HealthController::HealthValue + offset::HealthController::Current);
|
||||||
|
m_fHealthMax += m.Read<float>(healthValue + offset::HealthController::HealthValue + offset::HealthController::Maximum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayer::UpdateBone()
|
void CPlayer::UpdateBone()
|
||||||
{
|
{
|
||||||
m_vecHeadOrigin = GetBonePosition(BONE_HEAD);
|
m_vecHeadOrigin = GetBonePosition(BONE_HEAD);
|
||||||
m_vecNeckOrigin = GetBonePosition(BONE_NECK);
|
m_vecNeckOrigin = GetBonePosition(BONE_NECK);
|
||||||
|
m_vecBoneList.clear();
|
||||||
|
|
||||||
if (g.g_ESP_Skeleton)
|
if (!g.g_ESP_Skeleton)
|
||||||
{
|
return;
|
||||||
for (auto& id : PlayerBoneList)
|
|
||||||
{
|
|
||||||
Vector3 bone = GetBonePosition(id);
|
|
||||||
|
|
||||||
if (Vec3_Empty(bone)) {
|
m_vecBoneList.reserve(PlayerBoneList.size());
|
||||||
m_vecBoneList.clear();
|
for (const auto id : PlayerBoneList)
|
||||||
break;
|
{
|
||||||
}
|
const Vector3 bone = GetBonePosition(id);
|
||||||
|
if (Vec3_Empty(bone))
|
||||||
|
{
|
||||||
|
m_vecBoneList.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_vecBoneList.push_back(bone);
|
m_vecBoneList.push_back(bone);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPlayer::IsAiming()
|
bool CPlayer::IsAiming()
|
||||||
{
|
{
|
||||||
return m.Read<bool>(m_pWeaponAnimation + offset::WeaponAnimations::isAiming);
|
return m_pWeaponAnimation != 0 && m.Read<bool>(m_pWeaponAnimation + offset::WeaponAnimations::isAiming);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 CPlayer::GetBonePosition(const int BoneId)
|
Vector3 CPlayer::GetBonePosition(const int BoneId)
|
||||||
{
|
{
|
||||||
uintptr_t TransformPtr = m.Read<uintptr_t>(m_pBoneArray.address[BoneId] + 0x10);
|
constexpr int kBoneCount = static_cast<int>(sizeof(m_pBoneArray.address) / sizeof(m_pBoneArray.address[0]));
|
||||||
|
if (BoneId < 0 || BoneId >= kBoneCount)
|
||||||
|
return {};
|
||||||
|
|
||||||
return GetTransformPosition(TransformPtr);
|
const uintptr_t bone = m_pBoneArray.address[BoneId];
|
||||||
}
|
if (!bone)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
uintptr_t transform = m.Read<uintptr_t>(bone + 0x10);
|
||||||
|
if (!transform)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return GetTransformPosition(transform);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ public:
|
||||||
uintptr_t m_pProfile{ 0 };
|
uintptr_t m_pProfile{ 0 };
|
||||||
uintptr_t m_pInfo{ 0 };
|
uintptr_t m_pInfo{ 0 };
|
||||||
uintptr_t m_pSetting{ 0 };
|
uintptr_t m_pSetting{ 0 };
|
||||||
uintptr_t m_pBodyController{ 0 };
|
uintptr_t m_pHealthController{ 0 };
|
||||||
uintptr_t m_pWeaponAnimation{ 0 };
|
uintptr_t m_pWeaponAnimation{ 0 };
|
||||||
|
|
||||||
// データ
|
// データ
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@ float GetDistance(Vector3 value1, Vector3 value2)
|
||||||
|
|
||||||
Vector3 GetTransformPosition(uintptr_t& transform)
|
Vector3 GetTransformPosition(uintptr_t& transform)
|
||||||
{
|
{
|
||||||
|
if (!transform)
|
||||||
|
return {};
|
||||||
|
|
||||||
__m128 result{};
|
__m128 result{};
|
||||||
|
|
||||||
const __m128 mulVec0 = { -2.000, 2.000, -2.000, 0.000 };
|
const __m128 mulVec0 = { -2.000, 2.000, -2.000, 0.000 };
|
||||||
|
|
@ -29,6 +32,9 @@ Vector3 GetTransformPosition(uintptr_t& transform)
|
||||||
|
|
||||||
TransformAccessReadOnly pTransformAccessReadOnly = m.Read<TransformAccessReadOnly>(transform + 0x38);
|
TransformAccessReadOnly pTransformAccessReadOnly = m.Read<TransformAccessReadOnly>(transform + 0x38);
|
||||||
unsigned int Index = m.Read<unsigned int>(transform + 0x40);
|
unsigned int Index = m.Read<unsigned int>(transform + 0x40);
|
||||||
|
if (!pTransformAccessReadOnly.pTransformData)
|
||||||
|
return {};
|
||||||
|
|
||||||
TransformData transform_data = m.Read<TransformData>(pTransformAccessReadOnly.pTransformData + 0x18);
|
TransformData transform_data = m.Read<TransformData>(pTransformAccessReadOnly.pTransformData + 0x18);
|
||||||
|
|
||||||
if (transform_data.pTransformArray && transform_data.pTransformIndices)
|
if (transform_data.pTransformArray && transform_data.pTransformIndices)
|
||||||
|
|
@ -96,6 +102,9 @@ bool WorldToScreen(Matrix ViewMatrix, const Vector2& GameSize, Vector3& vIn, Vec
|
||||||
|
|
||||||
uintptr_t GetObjectFromList(uintptr_t listPtr, uintptr_t lastObjectPtr, const char* objectName)
|
uintptr_t GetObjectFromList(uintptr_t listPtr, uintptr_t lastObjectPtr, const char* objectName)
|
||||||
{
|
{
|
||||||
|
if (!listPtr || !objectName)
|
||||||
|
return 0;
|
||||||
|
|
||||||
char ObjectName[128]{};
|
char ObjectName[128]{};
|
||||||
uintptr_t classNamePtr = 0;
|
uintptr_t classNamePtr = 0;
|
||||||
BaseObject activeObject = m.Read<BaseObject>(listPtr);
|
BaseObject activeObject = m.Read<BaseObject>(listPtr);
|
||||||
|
|
@ -111,7 +120,8 @@ uintptr_t GetObjectFromList(uintptr_t listPtr, uintptr_t lastObjectPtr, const ch
|
||||||
if (strcmp(ObjectName, objectName) == 0)
|
if (strcmp(ObjectName, objectName) == 0)
|
||||||
return activeObject.object;
|
return activeObject.object;
|
||||||
|
|
||||||
Sleep(1);
|
if (!activeObject.nextObjectLink)
|
||||||
|
break;
|
||||||
|
|
||||||
activeObject = m.Read<BaseObject>(activeObject.nextObjectLink);
|
activeObject = m.Read<BaseObject>(activeObject.nextObjectLink);
|
||||||
}
|
}
|
||||||
|
|
@ -135,13 +145,22 @@ bool CGame::InitAddress()
|
||||||
{
|
{
|
||||||
// GameObjectManager
|
// GameObjectManager
|
||||||
uintptr_t pGOM = m.Read<uintptr_t>(m.m_gBaseAddress + offset::dwGameObjectManager);
|
uintptr_t pGOM = m.Read<uintptr_t>(m.m_gBaseAddress + offset::dwGameObjectManager);
|
||||||
|
if (!pGOM)
|
||||||
|
{
|
||||||
|
m_objGameObjectManager = {};
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_objGameObjectManager = m.Read<GameObjectManager>(pGOM);
|
m_objGameObjectManager = m.Read<GameObjectManager>(pGOM);
|
||||||
|
|
||||||
return m_objGameObjectManager.lastActiveObject != NULL ? true : false;
|
return m_objGameObjectManager.lastActiveObject != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGame::Update()
|
bool CGame::Update()
|
||||||
{
|
{
|
||||||
|
m_pGameWorld = 0;
|
||||||
|
m_pLocalGameWorld = 0;
|
||||||
|
|
||||||
// GameWorld
|
// GameWorld
|
||||||
uintptr_t activeNodes = m.Read<uintptr_t>(m_objGameObjectManager.ActiveNodes);
|
uintptr_t activeNodes = m.Read<uintptr_t>(m_objGameObjectManager.ActiveNodes);
|
||||||
uintptr_t lastActiveNode = m.Read<uintptr_t>(m_objGameObjectManager.LastActiveNode);
|
uintptr_t lastActiveNode = m.Read<uintptr_t>(m_objGameObjectManager.LastActiveNode);
|
||||||
|
|
@ -161,21 +180,30 @@ bool CGame::Update()
|
||||||
|
|
||||||
bool CGame::UpdateCamera()
|
bool CGame::UpdateCamera()
|
||||||
{
|
{
|
||||||
Camera all_cameras = m.Read<Camera>(m.Read<uintptr_t>(m.m_gBaseAddress + offset::dwAllCamera));
|
m_pFpsCamera = 0;
|
||||||
|
|
||||||
if (all_cameras.count == 0)
|
uintptr_t all_camera_ptr = m.Read<uintptr_t>(m.m_gBaseAddress + offset::dwAllCamera);
|
||||||
|
if (!all_camera_ptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Camera all_cameras = m.Read<Camera>(all_camera_ptr);
|
||||||
|
|
||||||
|
if (all_cameras.list == 0 || all_cameras.count == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (int i = 0; i < all_cameras.count; i++)
|
for (int i = 0; i < all_cameras.count; i++)
|
||||||
{
|
{
|
||||||
uintptr_t camera = m.Read<uintptr_t>(all_cameras.list + (i * 0x8));
|
uintptr_t camera = m.Read<uintptr_t>(all_cameras.list + (i * 0x8));
|
||||||
if (camera != NULL)
|
if (camera != 0)
|
||||||
{
|
{
|
||||||
uintptr_t camera_obj = m.Read<uintptr_t>(camera + 0x30);
|
uintptr_t camera_obj = m.Read<uintptr_t>(camera + 0x30);
|
||||||
|
if (!camera_obj)
|
||||||
|
continue;
|
||||||
|
|
||||||
uintptr_t camera_name_ptr = m.Read<uintptr_t>(camera_obj + 0x60);
|
uintptr_t camera_name_ptr = m.Read<uintptr_t>(camera_obj + 0x60);
|
||||||
|
|
||||||
if (!camera_name_ptr)
|
if (!camera_name_ptr)
|
||||||
return false;
|
continue;
|
||||||
|
|
||||||
char name[64]{};
|
char name[64]{};
|
||||||
m.ReadString(camera_name_ptr, name, sizeof(name));
|
m.ReadString(camera_name_ptr, name, sizeof(name));
|
||||||
|
|
@ -197,9 +225,17 @@ bool CGame::IsInRaid()
|
||||||
|
|
||||||
Matrix CGame::GetViewMatrix()
|
Matrix CGame::GetViewMatrix()
|
||||||
{
|
{
|
||||||
|
if (!m_pFpsCamera)
|
||||||
|
return {};
|
||||||
|
|
||||||
// ここ省略できるかチェック
|
// ここ省略できるかチェック
|
||||||
uintptr_t dw = m.Read<uintptr_t>(m_pFpsCamera + 0x30);
|
uintptr_t dw = m.Read<uintptr_t>(m_pFpsCamera + 0x30);
|
||||||
|
if (!dw)
|
||||||
|
return {};
|
||||||
|
|
||||||
uintptr_t viewmatrix_ptr = m.Read<uintptr_t>(dw + 0x18);
|
uintptr_t viewmatrix_ptr = m.Read<uintptr_t>(dw + 0x18);
|
||||||
|
if (!viewmatrix_ptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
return m.Read<Matrix>(viewmatrix_ptr + 0x100);
|
return m.Read<Matrix>(viewmatrix_ptr + 0x100);
|
||||||
}
|
}
|
||||||
|
|
@ -1,81 +1,88 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// by Unispect and UC
|
// by Unispect and UC
|
||||||
namespace offset
|
namespace offset
|
||||||
{
|
{
|
||||||
// Base
|
// Base (not present in dump.txt; keep the native UnityPlayer values used by this build)
|
||||||
constexpr auto dwGameObjectManager = 0x1CF93E0;
|
constexpr auto dwGameObjectManager = 0x1CF93E0;
|
||||||
constexpr auto dwAllCamera = 0x1BF8BC0;
|
constexpr auto dwAllCamera = 0x1BF8BC0;
|
||||||
|
|
||||||
// EFT.GameWorld
|
// EFT.GameWorld / EFT.ClientLocalGameWorld
|
||||||
constexpr auto ExfilController = 0x30;
|
constexpr auto ExfilController = 0x30;
|
||||||
constexpr auto LootList = 0x118;
|
constexpr auto LootList = 0x118;
|
||||||
constexpr auto RegisteredPlayers = 0x140;
|
constexpr auto RegisteredPlayers = 0x140;
|
||||||
constexpr auto MainPlayer = 0x1A8;
|
constexpr auto MainPlayer = 0x1A8;
|
||||||
constexpr auto GrenadeList = 0x200;
|
constexpr auto GrenadeList = 0x200;
|
||||||
|
|
||||||
// EFT.Player
|
// EFT.Player (dump.txt: EFT.Player)
|
||||||
namespace Player
|
namespace Player
|
||||||
{
|
{
|
||||||
constexpr auto pPlayerBody = 0xC0;
|
constexpr auto pPlayerBody = 0xC0; // _playerBody
|
||||||
constexpr auto pMovementContext = 0x1E0; // EXFIL DELTA (Mono 0.16.9) 实测. IL2CPP 0.15.x 是 0x170
|
constexpr auto pMovementContext = 0x58; // <MovementContext>k__BackingField
|
||||||
constexpr auto pWeaponAnimation = 0x1E0; // IL2CPP 版定义, Mono 版实际是 MovementContext (框架旧代码保留)
|
constexpr auto pWeaponAnimation = 0x1E0; // <ProceduralWeaponAnimation>k__BackingField
|
||||||
constexpr auto pProfile = 0x600;
|
constexpr auto pProfile = 0x618; // <Profile>k__BackingField
|
||||||
constexpr auto pPhysics = 0x610;
|
constexpr auto pPhysics = 0x630; // Physical
|
||||||
constexpr auto pHealthController = 0x640;
|
constexpr auto pHealthController = 0x660; // _healthController
|
||||||
}
|
}
|
||||||
|
|
||||||
// EFT.MovementContext
|
// EFT.MovementContext (dump.txt: EFT.MovementContext)
|
||||||
namespace MovementContext
|
namespace MovementContext
|
||||||
{
|
{
|
||||||
// Vector2 (x = yaw, y = pitch) [rad]
|
// Vector2 (x = yaw, y = pitch), in radians.
|
||||||
// EXFIL DELTA (Mono 0.16.9) 实测: +0x3AC = Rotation_1 (视角旋转)
|
constexpr auto Rotation = 0x27C; // Rotation_1
|
||||||
// +0x3A4 = MovementDirection_1 (移动方向, 勿用!) 依据 Mono.Cecil 字段表
|
}
|
||||||
constexpr auto Rotation = 0x3AC;
|
|
||||||
}
|
|
||||||
|
|
||||||
// EFT.Profile
|
// EFT.Profile
|
||||||
namespace Profile
|
namespace Profile
|
||||||
{
|
{
|
||||||
constexpr auto Id = 0x10; // str
|
constexpr auto Id = 0x10;
|
||||||
constexpr auto AccountId = 0x18; // str
|
constexpr auto AccountId = 0x18;
|
||||||
constexpr auto pInfoClass = 0x40; // pointer
|
constexpr auto pInfoClass = 0x40; // Info
|
||||||
}
|
}
|
||||||
|
|
||||||
// EFT.Profile->InfoClass
|
// EFT.Profile -> InfoClass
|
||||||
namespace InfoClass
|
namespace InfoClass
|
||||||
{
|
{
|
||||||
constexpr auto Nickname = 0x10; // str
|
constexpr auto Nickname = 0x10;
|
||||||
constexpr auto EntryPoint = 0x18; // str
|
constexpr auto EntryPoint = 0x18;
|
||||||
constexpr auto MainProfileNickname = 0x20; // str
|
constexpr auto MainProfileNickname = 0x20;
|
||||||
constexpr auto MGroupId = 0x28; // str
|
constexpr auto MGroupId = 0x28;
|
||||||
constexpr auto TeamId = 0x30; // str
|
constexpr auto TeamId = 0x30;
|
||||||
constexpr auto profileInfoSettingsClass = 0x50; // pointer
|
constexpr auto profileInfoSettingsClass = 0x48; // ProfileInfoSettingsClass
|
||||||
constexpr auto eplayerSide_0 = 0x90; // int
|
constexpr auto eplayerSide_0 = 0x88;
|
||||||
constexpr auto RegistrationDate = 0x94; // int
|
constexpr auto RegistrationDate = 0x8C;
|
||||||
constexpr auto Type = 0x98; // int
|
constexpr auto Type = 0x90;
|
||||||
}
|
}
|
||||||
|
|
||||||
// EFT.Player->.BasePhysicalClass
|
// EFT.HealthSystem.ActiveHealthController / GClass3009<T>
|
||||||
namespace Physics
|
namespace HealthController
|
||||||
{
|
{
|
||||||
|
constexpr auto BodyParts = 0x68; // Dictionary<int, BodyPartState<T>>
|
||||||
|
constexpr auto DictionaryEntries = 0x18;
|
||||||
|
constexpr auto DictionaryCount = 0x40;
|
||||||
|
constexpr auto ArrayData = 0x20;
|
||||||
|
constexpr auto EntryStride = 0x18;
|
||||||
|
constexpr auto EntryValue = 0x10;
|
||||||
|
constexpr auto BodyPartHealth = 0x10; // BodyPartState.Health
|
||||||
|
constexpr auto HealthValue = 0x10; // HealthValue.Value
|
||||||
|
constexpr auto Current = 0x00;
|
||||||
|
constexpr auto Maximum = 0x04;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
// EFT.Animations.ProceduralWeaponAnimation
|
||||||
|
namespace WeaponAnimations
|
||||||
|
{
|
||||||
|
constexpr auto Breath = 0x30;
|
||||||
|
constexpr auto isAiming = 0x1C5;
|
||||||
|
}
|
||||||
|
|
||||||
// EFT.Animations.ProceduralWeaponAnimation
|
// .BasePhysicalClass
|
||||||
namespace WeaponAnimations
|
namespace Physics
|
||||||
{
|
{
|
||||||
constexpr auto Breath = 0x30;
|
constexpr auto Stamina = 0x38;
|
||||||
constexpr auto isAiming = 0x1C5;
|
constexpr auto HandsStamina = 0x40;
|
||||||
}
|
constexpr auto Oxygen = 0x48;
|
||||||
|
constexpr auto FallDamageMultiplier = 0xBC;
|
||||||
// .BasePhysicalClass
|
constexpr auto OxygenRestoreRate = 0xD4;
|
||||||
namespace Physics
|
}
|
||||||
{
|
}
|
||||||
constexpr auto Stamina = 0x38;
|
|
||||||
constexpr auto HandsStamina = 0x40;
|
|
||||||
constexpr auto Oxygen = 0x40;
|
|
||||||
constexpr auto FallDamageMultiplier = 0xBC;
|
|
||||||
constexpr auto OxygenRestoreRate = 0xD4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -91,12 +91,13 @@ void CFramework::UpdateStaticList() // C6262 :(
|
||||||
|
|
||||||
std::vector<CItem> list_item{};
|
std::vector<CItem> list_item{};
|
||||||
std::vector<CExfil> list_exfil{};
|
std::vector<CExfil> list_exfil{};
|
||||||
const auto GameWorld = tarkov->m_pLocalGameWorld;
|
|
||||||
tarkov->UpdateCamera();
|
tarkov->UpdateCamera();
|
||||||
|
|
||||||
// ItemList
|
// ItemList
|
||||||
if (tarkov->Update())
|
if (tarkov->Update())
|
||||||
{
|
{
|
||||||
|
const auto GameWorld = tarkov->m_pLocalGameWorld;
|
||||||
|
|
||||||
// Exfil
|
// Exfil
|
||||||
if (g.g_ESP_Exfil)
|
if (g.g_ESP_Exfil)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -53,13 +53,11 @@ struct Globals
|
||||||
float g_RecoilStrength = 4.f; // 每次下拉的鼠标单位(mickeys)
|
float g_RecoilStrength = 4.f; // 每次下拉的鼠标单位(mickeys)
|
||||||
int g_RecoilInterval = 15; // 下拉间隔 [ms]
|
int g_RecoilInterval = 15; // 下拉间隔 [ms]
|
||||||
|
|
||||||
// Aim Offset (运行时可调, 默认 = 本客户端实测值)
|
// Aim Offset (运行时可调, 由 F:\desktop\Release\dump.txt 校准)
|
||||||
// Memory 模式自瞄用: Player + g_AimMcOffset -> + g_AimRotOffset (Vector2 yaw/pitch)
|
// Memory 模式自瞄用: Player + g_AimMcOffset -> + g_AimRotOffset (Vector2 yaw/pitch)
|
||||||
// EXFIL DELTA (Mono 0.16.9) 实测: Player+0x1E0 = MovementContext
|
// EFT.Player: MovementContext = +0x58; EFT.MovementContext: Rotation_1 = +0x27C
|
||||||
// +0x3A4 = MovementDirection(移动方向, 非视角!), +0x3AC = Rotation_1(视角旋转, 正解)
|
int g_AimMcOffset = 0x58;
|
||||||
// 依据: Mono.Cecil 字段表 + 运行时验证 (0x3A4 读出的俯仰恒 0)
|
int g_AimRotOffset = 0x27C;
|
||||||
int g_AimMcOffset = 0x1E0;
|
|
||||||
int g_AimRotOffset = 0x3AC;
|
|
||||||
|
|
||||||
// System
|
// System
|
||||||
bool g_StreamProof = false;
|
bool g_StreamProof = false;
|
||||||
|
|
|
||||||
|
|
@ -58,19 +58,24 @@ uintptr_t Memory::GetModuleBase(const std::string moduleName)
|
||||||
entry.dwSize = sizeof(MODULEENTRY32);
|
entry.dwSize = sizeof(MODULEENTRY32);
|
||||||
const auto snapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, PID);
|
const auto snapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, PID);
|
||||||
|
|
||||||
while (Module32Next(snapShot, &entry))
|
if (snapShot == INVALID_HANDLE_VALUE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (Module32First(snapShot, &entry))
|
||||||
{
|
{
|
||||||
if (!moduleName.compare(entry.szModule))
|
do
|
||||||
{
|
{
|
||||||
CloseHandle(snapShot);
|
if (!moduleName.compare(entry.szModule))
|
||||||
return reinterpret_cast<uintptr_t>(entry.modBaseAddr);
|
{
|
||||||
}
|
const auto base = reinterpret_cast<uintptr_t>(entry.modBaseAddr);
|
||||||
|
CloseHandle(snapShot);
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
} while (Module32Next(snapShot, &entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snapShot)
|
CloseHandle(snapShot);
|
||||||
CloseHandle(snapShot);
|
return 0;
|
||||||
|
|
||||||
return reinterpret_cast<uintptr_t>(entry.modBaseAddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PROCESSENTRY32 Memory::GetProcess(const std::string processName)
|
PROCESSENTRY32 Memory::GetProcess(const std::string processName)
|
||||||
|
|
@ -79,17 +84,22 @@ PROCESSENTRY32 Memory::GetProcess(const std::string processName)
|
||||||
entry.dwSize = sizeof(PROCESSENTRY32);
|
entry.dwSize = sizeof(PROCESSENTRY32);
|
||||||
const auto snapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
|
const auto snapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
|
||||||
|
|
||||||
while (Process32Next(snapShot, &entry))
|
if (snapShot == INVALID_HANDLE_VALUE)
|
||||||
|
return PROCESSENTRY32();
|
||||||
|
|
||||||
|
if (Process32First(snapShot, &entry))
|
||||||
{
|
{
|
||||||
if (!processName.compare(entry.szExeFile))
|
do
|
||||||
{
|
{
|
||||||
CloseHandle(snapShot);
|
if (!processName.compare(entry.szExeFile))
|
||||||
return entry;
|
{
|
||||||
}
|
CloseHandle(snapShot);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
} while (Process32Next(snapShot, &entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(snapShot);
|
CloseHandle(snapShot);
|
||||||
|
|
||||||
return PROCESSENTRY32();
|
return PROCESSENTRY32();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,17 @@ public:
|
||||||
}
|
}
|
||||||
uintptr_t ReadChain(uintptr_t address, const std::vector<uintptr_t>& offsets)
|
uintptr_t ReadChain(uintptr_t address, const std::vector<uintptr_t>& offsets)
|
||||||
{
|
{
|
||||||
uintptr_t result = Read<uintptr_t>(address + offsets.at(0));
|
if (!address || offsets.empty())
|
||||||
for (int i = 1; i < offsets.size(); i++)
|
return 0;
|
||||||
result = Read<uintptr_t>(result + offsets.at(i));
|
|
||||||
|
uintptr_t result = Read<uintptr_t>(address + offsets.front());
|
||||||
|
for (std::size_t i = 1; i < offsets.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!result)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
result = Read<uintptr_t>(result + offsets[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -62,9 +70,17 @@ public:
|
||||||
}
|
}
|
||||||
std::string ReadString(uintptr_t address, int length)
|
std::string ReadString(uintptr_t address, int length)
|
||||||
{
|
{
|
||||||
static char Buffer[256]{};
|
if (!address || length <= 0)
|
||||||
ReadProcessMemory(pHandle, (void*)(address), Buffer, length, nullptr);
|
return {};
|
||||||
|
|
||||||
|
char Buffer[256]{};
|
||||||
|
if (length >= static_cast<int>(sizeof(Buffer)))
|
||||||
|
length = static_cast<int>(sizeof(Buffer)) - 1;
|
||||||
|
|
||||||
|
if (!ReadProcessMemory(pHandle, reinterpret_cast<void*>(address), Buffer, length, nullptr))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
Buffer[length] = '\0';
|
||||||
return std::string(Buffer);
|
return std::string(Buffer);
|
||||||
};
|
};
|
||||||
wchar_t* ReadWString(uintptr_t address, int length)
|
wchar_t* ReadWString(uintptr_t address, int length)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue