diff options
| -rw-r--r-- | src/bones.cpp | 134 | ||||
| -rw-r--r-- | src/esp.cpp | 8 | ||||
| -rw-r--r-- | src/hl2h.h | 1 |
3 files changed, 115 insertions, 28 deletions
diff --git a/src/bones.cpp b/src/bones.cpp index 2ff282b..bba61b9 100644 --- a/src/bones.cpp +++ b/src/bones.cpp | |||
| @@ -136,6 +136,76 @@ static const char *bone_name_raw(const StudioHdr *h, int i) { | |||
| 136 | return n[0] ? n : nullptr; | 136 | return n[0] ? n : nullptr; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | static const HitboxSet *hitbox_set0(const StudioHdr *h) { | ||
| 140 | if (!h || h->numhitboxsets <= 0 || h->hitboxsetindex <= 0) | ||
| 141 | return nullptr; | ||
| 142 | const HitboxSet *s = | ||
| 143 | (const HitboxSet *)((const uint8_t *)h + h->hitboxsetindex); | ||
| 144 | if (s->numhitboxes <= 0 || s->numhitboxes > 512 || s->hitboxindex <= 0) | ||
| 145 | return nullptr; | ||
| 146 | return s; | ||
| 147 | } | ||
| 148 | |||
| 149 | static const Hitbox *hitboxes(const HitboxSet *s) { | ||
| 150 | return (const Hitbox *)((const uint8_t *)s + s->hitboxindex); | ||
| 151 | } | ||
| 152 | |||
| 153 | static const char *hitbox_name(const Hitbox &b) { | ||
| 154 | if (b.szhitboxnameindex <= 0 || b.szhitboxnameindex > 0x10000) | ||
| 155 | return ""; | ||
| 156 | return (const char *)&b + b.szhitboxnameindex; | ||
| 157 | } | ||
| 158 | |||
| 159 | static bool contains_ci(const char *hay, const char *needle) { | ||
| 160 | if (!hay || !needle || !*needle) | ||
| 161 | return false; | ||
| 162 | size_t n = strlen(needle); | ||
| 163 | for (const char *p = hay; *p; p++) | ||
| 164 | if (strncasecmp(p, needle, n) == 0) | ||
| 165 | return true; | ||
| 166 | return false; | ||
| 167 | } | ||
| 168 | |||
| 169 | static bool hitbox_world(const BoneEntry *e, const Hitbox &b, Vector &out) { | ||
| 170 | if (b.bone < 0 || b.bone >= e->count) | ||
| 171 | return false; | ||
| 172 | Vector local{(b.bbmin.x + b.bbmax.x) * 0.5f, | ||
| 173 | (b.bbmin.y + b.bbmax.y) * 0.5f, | ||
| 174 | (b.bbmin.z + b.bbmax.z) * 0.5f}; | ||
| 175 | const Matrix3x4 &m = e->mats[b.bone]; | ||
| 176 | out.x = | ||
| 177 | local.x * m.m[0][0] + local.y * m.m[0][1] + local.z * m.m[0][2] + m.m[0][3]; | ||
| 178 | out.y = | ||
| 179 | local.x * m.m[1][0] + local.y * m.m[1][1] + local.z * m.m[1][2] + m.m[1][3]; | ||
| 180 | out.z = | ||
| 181 | local.x * m.m[2][0] + local.y * m.m[2][1] + local.z * m.m[2][2] + m.m[2][3]; | ||
| 182 | return true; | ||
| 183 | } | ||
| 184 | |||
| 185 | static void dump_hitboxes(const BoneEntry *e) { | ||
| 186 | const StudioHdr *h = e->hdr; | ||
| 187 | logf("hitbox dump: idx=%d sets=%d setidx=%d", e->idx, h->numhitboxsets, | ||
| 188 | h->hitboxsetindex); | ||
| 189 | const HitboxSet *s = hitbox_set0(h); | ||
| 190 | if (!s) { | ||
| 191 | logf("hitbox dump: no usable hitbox set"); | ||
| 192 | return; | ||
| 193 | } | ||
| 194 | const Hitbox *hb = hitboxes(s); | ||
| 195 | logf("hitbox dump: set0 n=%d hitboxindex=%d", s->numhitboxes, | ||
| 196 | s->hitboxindex); | ||
| 197 | int n = s->numhitboxes < 24 ? s->numhitboxes : 24; | ||
| 198 | for (int i = 0; i < n; i++) { | ||
| 199 | const char *bn = (hb[i].bone >= 0 && hb[i].bone < e->count) | ||
| 200 | ? bone_name_raw(h, hb[i].bone) | ||
| 201 | : nullptr; | ||
| 202 | logf(" hb %d name='%s' bone=%d(%s) bb=(%.1f %.1f %.1f)-(%.1f %.1f %.1f)", | ||
| 203 | i, hitbox_name(hb[i]), hb[i].bone, bn ? bn : "?", hb[i].bbmin.x, | ||
| 204 | hb[i].bbmin.y, hb[i].bbmin.z, hb[i].bbmax.x, hb[i].bbmax.y, | ||
| 205 | hb[i].bbmax.z); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 139 | } // namespace | 209 | } // namespace |
| 140 | 210 | ||
| 141 | bool bones_update(int idx, void *ent) { | 211 | bool bones_update(int idx, void *ent) { |
| @@ -253,36 +323,46 @@ bool hitbox_center(int idx, const char *name, Vector &out) { | |||
| 253 | BoneEntry *e = find_entry(idx); | 323 | BoneEntry *e = find_entry(idx); |
| 254 | if (!e || !e->valid || !name || !e->hdr) | 324 | if (!e || !e->valid || !name || !e->hdr) |
| 255 | return false; | 325 | return false; |
| 256 | const StudioHdr *h = e->hdr; | 326 | const HitboxSet *s = hitbox_set0(e->hdr); |
| 257 | if (h->numhitboxsets <= 0 || h->hitboxsetindex <= 0) | 327 | if (!s) |
| 258 | return false; | 328 | return false; |
| 259 | const HitboxSet *set = | 329 | const Hitbox *boxes = hitboxes(s); |
| 260 | (const HitboxSet *)((const uint8_t *)h + h->hitboxsetindex); | 330 | for (int i = 0; i < s->numhitboxes; i++) { |
| 261 | if (set->numhitboxes <= 0 || set->numhitboxes > 512 || | 331 | if (strcasecmp(hitbox_name(boxes[i]), name) == 0) |
| 262 | set->hitboxindex <= 0) | 332 | return hitbox_world(e, boxes[i], out); |
| 333 | } | ||
| 334 | return false; | ||
| 335 | } | ||
| 336 | |||
| 337 | // Head position with fallbacks, because several HL2 models have no hitbox | ||
| 338 | // names: exact "head" hitbox -> hitbox whose bone name contains "head" -> | ||
| 339 | // head bone origin. Dumps the hitbox set once for diagnosis. | ||
| 340 | bool head_position(int idx, Vector &out) { | ||
| 341 | BoneEntry *e = find_entry(idx); | ||
| 342 | if (!e || !e->valid || !e->hdr) | ||
| 263 | return false; | 343 | return false; |
| 264 | const Hitbox *boxes = | 344 | static bool dumped = false; |
| 265 | (const Hitbox *)((const uint8_t *)set + set->hitboxindex); | 345 | if (!dumped) { |
| 266 | for (int i = 0; i < set->numhitboxes; i++) { | 346 | dumped = true; |
| 267 | const Hitbox &b = boxes[i]; | 347 | dump_hitboxes(e); |
| 268 | if (b.szhitboxnameindex <= 0) | 348 | } |
| 269 | continue; | 349 | if (hitbox_center(idx, "head", out)) |
| 270 | const char *hn = (const char *)&b + b.szhitboxnameindex; | ||
| 271 | if (strcasecmp(hn, name) != 0) | ||
| 272 | continue; | ||
| 273 | if (b.bone < 0 || b.bone >= e->count) | ||
| 274 | return false; | ||
| 275 | Vector local{(b.bbmin.x + b.bbmax.x) * 0.5f, | ||
| 276 | (b.bbmin.y + b.bbmax.y) * 0.5f, | ||
| 277 | (b.bbmin.z + b.bbmax.z) * 0.5f}; | ||
| 278 | const Matrix3x4 &m = e->mats[b.bone]; | ||
| 279 | out.x = local.x * m.m[0][0] + local.y * m.m[0][1] + local.z * m.m[0][2] + | ||
| 280 | m.m[0][3]; | ||
| 281 | out.y = local.x * m.m[1][0] + local.y * m.m[1][1] + local.z * m.m[1][2] + | ||
| 282 | m.m[1][3]; | ||
| 283 | out.z = local.x * m.m[2][0] + local.y * m.m[2][1] + local.z * m.m[2][2] + | ||
| 284 | m.m[2][3]; | ||
| 285 | return true; | 350 | return true; |
| 351 | const HitboxSet *s = hitbox_set0(e->hdr); | ||
| 352 | if (s) { | ||
| 353 | const Hitbox *boxes = hitboxes(s); | ||
| 354 | for (int i = 0; i < s->numhitboxes; i++) { | ||
| 355 | if (boxes[i].bone < 0 || boxes[i].bone >= e->count) | ||
| 356 | continue; | ||
| 357 | const char *bn = bone_name_raw(e->hdr, boxes[i].bone); | ||
| 358 | if (bn && contains_ci(bn, "head")) | ||
| 359 | return hitbox_world(e, boxes[i], out); | ||
| 360 | } | ||
| 361 | } | ||
| 362 | for (int i = 0; i < e->count; i++) { | ||
| 363 | const char *bn = bone_name_raw(e->hdr, i); | ||
| 364 | if (bn && contains_ci(bn, "head")) | ||
| 365 | return bone_pos(idx, i, out); | ||
| 286 | } | 366 | } |
| 287 | return false; | 367 | return false; |
| 288 | } | 368 | } |
diff --git a/src/esp.cpp b/src/esp.cpp index b384bc4..996a886 100644 --- a/src/esp.cpp +++ b/src/esp.cpp | |||
| @@ -334,8 +334,14 @@ void esp_draw() { | |||
| 334 | if (!ent || !bones_update(t.idx, ent)) | 334 | if (!ent || !bones_update(t.idx, ent)) |
| 335 | continue; | 335 | continue; |
| 336 | Vector head; | 336 | Vector head; |
| 337 | if (!hitbox_center(t.idx, "head", head)) | 337 | if (!head_position(t.idx, head)) { |
| 338 | static int no_head = 0; | ||
| 339 | if (no_head < 4) { | ||
| 340 | no_head++; | ||
| 341 | logf("head: idx=%d no head hitbox/bone", t.idx); | ||
| 342 | } | ||
| 338 | continue; | 343 | continue; |
| 344 | } | ||
| 339 | float hx, hy; | 345 | float hx, hy; |
| 340 | if (!world_to_screen(head, hx, hy)) | 346 | if (!world_to_screen(head, hx, hy)) |
| 341 | continue; | 347 | continue; |
| @@ -175,6 +175,7 @@ int bone_find(int idx, const char *name); | |||
| 175 | int bone_parent(int idx, int bone); | 175 | int bone_parent(int idx, int bone); |
| 176 | bool bone_pos(int idx, int bone, Vector &out); | 176 | bool bone_pos(int idx, int bone, Vector &out); |
| 177 | bool hitbox_center(int idx, const char *hitbox_name, Vector &out); | 177 | bool hitbox_center(int idx, const char *hitbox_name, Vector &out); |
| 178 | bool head_position(int idx, Vector &out); | ||
| 178 | 179 | ||
| 179 | void outer_draw(); | 180 | void outer_draw(); |
| 180 | // raw ISurface slot calls used by the PaintTraverseEx hook (hl2h.cpp) | 181 | // raw ISurface slot calls used by the PaintTraverseEx hook (hl2h.cpp) |
