diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-26 16:20:05 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-26 16:20:24 +0100 |
| commit | a3e769a2a8d6f04fdae4e97d2a39d45e1cb062b8 (patch) | |
| tree | e3d15ab891bd52027055229dacde967c1c45226f | |
| parent | ESP: skeleton ESP (diff) | |
| download | hl2h-a3e769a2a8d6f04fdae4e97d2a39d45e1cb062b8.tar.gz hl2h-a3e769a2a8d6f04fdae4e97d2a39d45e1cb062b8.zip | |
ESP: restrict skeleton to humanoid core bones (no fingers/toes/headcrab)
| -rw-r--r-- | src/bones.cpp | 39 | ||||
| -rw-r--r-- | src/esp.cpp | 16 | ||||
| -rw-r--r-- | 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) { | |||
| 182 | return true; | 182 | return true; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | // HL2 humanoids (combine, metrocop, citizen, zombie, ...) use the ValveBiped | ||
| 186 | // skeleton. Draw only the core chain: pelvis/spine/neck/head, clavicle to | ||
| 187 | // hand, thigh to foot. Fingers, toes and extra model bones (e.g. the headcrab | ||
| 188 | // on a zombie) are skipped. | ||
| 189 | static bool core_bone_name(const char *n) { | ||
| 190 | if (!n || strncasecmp(n, "ValveBiped.Bip01_", 17) != 0) | ||
| 191 | return false; | ||
| 192 | if (contains_ci(n, "Finger") || contains_ci(n, "Toe") || | ||
| 193 | contains_ci(n, "Headcrab")) | ||
| 194 | return false; | ||
| 195 | static const char *tokens[] = {"Pelvis", "Spine", "Neck", "Head1", | ||
| 196 | "Clavicle", "UpperArm", "Forearm", "Hand", | ||
| 197 | "Thigh", "Calf", "Foot", nullptr}; | ||
| 198 | for (int i = 0; tokens[i]; i++) | ||
| 199 | if (contains_ci(n, tokens[i])) | ||
| 200 | return true; | ||
| 201 | return false; | ||
| 202 | } | ||
| 203 | |||
| 185 | static void dump_hitboxes(const BoneEntry *e) { | 204 | static void dump_hitboxes(const BoneEntry *e) { |
| 186 | const StudioHdr *h = e->hdr; | 205 | const StudioHdr *h = e->hdr; |
| 187 | logf("hitbox dump: idx=%d sets=%d setidx=%d", e->idx, h->numhitboxsets, | 206 | logf("hitbox dump: idx=%d sets=%d setidx=%d", e->idx, h->numhitboxsets, |
| @@ -312,6 +331,26 @@ int bone_parent(int idx, int bone) { | |||
| 312 | return bone_at(e->hdr, bone)->parent; | 331 | return bone_at(e->hdr, bone)->parent; |
| 313 | } | 332 | } |
| 314 | 333 | ||
| 334 | bool bone_is_skeleton_core(int idx, int bone) { | ||
| 335 | BoneEntry *e = find_entry(idx); | ||
| 336 | if (!e || !e->valid || bone < 0 || bone >= e->count) | ||
| 337 | return false; | ||
| 338 | return core_bone_name(bone_name_raw(e->hdr, bone)); | ||
| 339 | } | ||
| 340 | |||
| 341 | int bone_nearest_core_parent(int idx, int bone) { | ||
| 342 | BoneEntry *e = find_entry(idx); | ||
| 343 | if (!e || !e->valid || bone < 0 || bone >= e->count) | ||
| 344 | return -1; | ||
| 345 | int p = bone_at(e->hdr, bone)->parent; | ||
| 346 | for (int guard = 0; p >= 0 && p < e->count && guard < 64; guard++) { | ||
| 347 | if (core_bone_name(bone_name_raw(e->hdr, p))) | ||
| 348 | return p; | ||
| 349 | p = bone_at(e->hdr, p)->parent; | ||
| 350 | } | ||
| 351 | return -1; | ||
| 352 | } | ||
| 353 | |||
| 315 | bool bone_pos(int idx, int bone, Vector &out) { | 354 | bool bone_pos(int idx, int bone, Vector &out) { |
| 316 | BoneEntry *e = find_entry(idx); | 355 | BoneEntry *e = find_entry(idx); |
| 317 | if (!e || !e->valid || bone < 0 || bone >= e->count) | 356 | 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) { | |||
| 285 | Vector wp[256]; | 285 | Vector wp[256]; |
| 286 | float xs[256], ys[256]; | 286 | float xs[256], ys[256]; |
| 287 | bool ok[256]; | 287 | bool ok[256]; |
| 288 | int core_count = 0; | ||
| 288 | for (int i = 0; i < n; i++) { | 289 | for (int i = 0; i < n; i++) { |
| 290 | ok[i] = false; | ||
| 291 | if (!bone_is_skeleton_core(t.idx, i)) | ||
| 292 | continue; | ||
| 293 | core_count++; | ||
| 289 | ok[i] = bone_pos(t.idx, i, wp[i]) && | 294 | ok[i] = bone_pos(t.idx, i, wp[i]) && |
| 290 | world_to_screen(wp[i], xs[i], ys[i]) && std::isfinite(xs[i]) && | 295 | world_to_screen(wp[i], xs[i], ys[i]) && std::isfinite(xs[i]) && |
| 291 | std::isfinite(ys[i]); | 296 | std::isfinite(ys[i]); |
| 292 | } | 297 | } |
| 298 | static int logged = 0; | ||
| 299 | if (core_count > 0 && logged < 4) { | ||
| 300 | logged++; | ||
| 301 | logf("skeleton: idx=%d bones=%d core=%d", t.idx, n, core_count); | ||
| 302 | } | ||
| 293 | if (t.friendly) | 303 | if (t.friendly) |
| 294 | surf_color(60, 255, 60, 255); | 304 | surf_color(60, 255, 60, 255); |
| 295 | else if (t.neutral) | 305 | else if (t.neutral) |
| @@ -297,8 +307,10 @@ static void draw_skeleton(const EspTarget &t) { | |||
| 297 | else | 307 | else |
| 298 | surf_color(255, 60, 60, 255); | 308 | surf_color(255, 60, 60, 255); |
| 299 | for (int i = 0; i < n; i++) { | 309 | for (int i = 0; i < n; i++) { |
| 300 | int p = bone_parent(t.idx, i); | 310 | if (!ok[i]) |
| 301 | if (p >= 0 && p < n && ok[i] && ok[p]) | 311 | continue; |
| 312 | int p = bone_nearest_core_parent(t.idx, i); | ||
| 313 | if (p >= 0 && p < n && ok[p]) | ||
| 302 | surf_line((int)xs[p], (int)ys[p], (int)xs[i], (int)ys[i]); | 314 | surf_line((int)xs[p], (int)ys[p], (int)xs[i], (int)ys[i]); |
| 303 | } | 315 | } |
| 304 | } | 316 | } |
| @@ -175,6 +175,8 @@ int bones_count(int idx); | |||
| 175 | int bone_find(int idx, const char *name); | 175 | int bone_find(int idx, const char *name); |
| 176 | int bone_parent(int idx, int bone); | 176 | int bone_parent(int idx, int bone); |
| 177 | bool bone_pos(int idx, int bone, Vector &out); | 177 | bool bone_pos(int idx, int bone, Vector &out); |
| 178 | bool bone_is_skeleton_core(int idx, int bone); | ||
| 179 | int bone_nearest_core_parent(int idx, int bone); | ||
| 178 | bool hitbox_center(int idx, const char *hitbox_name, Vector &out); | 180 | bool hitbox_center(int idx, const char *hitbox_name, Vector &out); |
| 179 | bool head_position(int idx, Vector &out); | 181 | bool head_position(int idx, Vector &out); |
| 180 | 182 | ||
