From a3e769a2a8d6f04fdae4e97d2a39d45e1cb062b8 Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 26 Oct 2026 16:20:05 +0100 Subject: ESP: restrict skeleton to humanoid core bones (no fingers/toes/headcrab) --- src/bones.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/esp.cpp | 16 ++++++++++++++-- src/hl2h.h | 2 ++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/bones.cpp b/src/bones.cpp index 88aa429..a9c6887 100644 --- a/src/bones.cpp +++ b/src/bones.cpp @@ -182,6 +182,25 @@ static bool hitbox_world(const BoneEntry *e, const Hitbox &b, Vector &out) { return true; } +// HL2 humanoids (combine, metrocop, citizen, zombie, ...) use the ValveBiped +// skeleton. Draw only the core chain: pelvis/spine/neck/head, clavicle to +// hand, thigh to foot. Fingers, toes and extra model bones (e.g. the headcrab +// on a zombie) are skipped. +static bool core_bone_name(const char *n) { + if (!n || strncasecmp(n, "ValveBiped.Bip01_", 17) != 0) + return false; + if (contains_ci(n, "Finger") || contains_ci(n, "Toe") || + contains_ci(n, "Headcrab")) + return false; + static const char *tokens[] = {"Pelvis", "Spine", "Neck", "Head1", + "Clavicle", "UpperArm", "Forearm", "Hand", + "Thigh", "Calf", "Foot", nullptr}; + for (int i = 0; tokens[i]; i++) + if (contains_ci(n, tokens[i])) + return true; + return false; +} + static void dump_hitboxes(const BoneEntry *e) { const StudioHdr *h = e->hdr; logf("hitbox dump: idx=%d sets=%d setidx=%d", e->idx, h->numhitboxsets, @@ -312,6 +331,26 @@ int bone_parent(int idx, int bone) { return bone_at(e->hdr, bone)->parent; } +bool bone_is_skeleton_core(int idx, int bone) { + BoneEntry *e = find_entry(idx); + if (!e || !e->valid || bone < 0 || bone >= e->count) + return false; + return core_bone_name(bone_name_raw(e->hdr, bone)); +} + +int bone_nearest_core_parent(int idx, int bone) { + BoneEntry *e = find_entry(idx); + if (!e || !e->valid || bone < 0 || bone >= e->count) + return -1; + int p = bone_at(e->hdr, bone)->parent; + for (int guard = 0; p >= 0 && p < e->count && guard < 64; guard++) { + if (core_bone_name(bone_name_raw(e->hdr, p))) + return p; + p = bone_at(e->hdr, p)->parent; + } + return -1; +} + bool bone_pos(int idx, int bone, Vector &out) { BoneEntry *e = find_entry(idx); if (!e || !e->valid || bone < 0 || bone >= e->count) diff --git a/src/esp.cpp b/src/esp.cpp index b75a7a9..b5cb9b0 100644 --- a/src/esp.cpp +++ b/src/esp.cpp @@ -285,11 +285,21 @@ static void draw_skeleton(const EspTarget &t) { Vector wp[256]; float xs[256], ys[256]; bool ok[256]; + int core_count = 0; for (int i = 0; i < n; i++) { + ok[i] = false; + if (!bone_is_skeleton_core(t.idx, i)) + continue; + core_count++; ok[i] = bone_pos(t.idx, i, wp[i]) && world_to_screen(wp[i], xs[i], ys[i]) && std::isfinite(xs[i]) && std::isfinite(ys[i]); } + static int logged = 0; + if (core_count > 0 && logged < 4) { + logged++; + logf("skeleton: idx=%d bones=%d core=%d", t.idx, n, core_count); + } if (t.friendly) surf_color(60, 255, 60, 255); else if (t.neutral) @@ -297,8 +307,10 @@ static void draw_skeleton(const EspTarget &t) { else surf_color(255, 60, 60, 255); for (int i = 0; i < n; i++) { - int p = bone_parent(t.idx, i); - if (p >= 0 && p < n && ok[i] && ok[p]) + if (!ok[i]) + continue; + int p = bone_nearest_core_parent(t.idx, i); + if (p >= 0 && p < n && ok[p]) surf_line((int)xs[p], (int)ys[p], (int)xs[i], (int)ys[i]); } } diff --git a/src/hl2h.h b/src/hl2h.h index 1eaee10..c0d4cdd 100644 --- a/src/hl2h.h +++ b/src/hl2h.h @@ -175,6 +175,8 @@ int bones_count(int idx); int bone_find(int idx, const char *name); int bone_parent(int idx, int bone); bool bone_pos(int idx, int bone, Vector &out); +bool bone_is_skeleton_core(int idx, int bone); +int bone_nearest_core_parent(int idx, int bone); bool hitbox_center(int idx, const char *hitbox_name, Vector &out); bool head_position(int idx, Vector &out); -- cgit v1.2.3