summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bones.cpp134
-rw-r--r--src/esp.cpp8
-rw-r--r--src/hl2h.h1
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
139static 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
149static const Hitbox *hitboxes(const HitboxSet *s) {
150 return (const Hitbox *)((const uint8_t *)s + s->hitboxindex);
151}
152
153static 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
159static 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
169static 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
185static 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
141bool bones_update(int idx, void *ent) { 211bool 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.
340bool 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;
diff --git a/src/hl2h.h b/src/hl2h.h
index d57105d..68d5d55 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -175,6 +175,7 @@ int bone_find(int idx, const char *name);
175int bone_parent(int idx, int bone); 175int bone_parent(int idx, int bone);
176bool bone_pos(int idx, int bone, Vector &out); 176bool bone_pos(int idx, int bone, Vector &out);
177bool hitbox_center(int idx, const char *hitbox_name, Vector &out); 177bool hitbox_center(int idx, const char *hitbox_name, Vector &out);
178bool head_position(int idx, Vector &out);
178 179
179void outer_draw(); 180void 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)