summaryrefslogtreecommitdiffstats
path: root/src/vischeck.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-26 17:22:25 +0100
committersalmonik <salmonik@tuta.io>2026-10-26 17:22:25 +0100
commite9944657c7ddefb3b8d2c8373c97fa47629ea1b8 (patch)
treed79bb7b262b5791d05f1a087b0db4515ce69b47d /src/vischeck.cpp
parentAimbot v3: world-only vischeck (diff)
downloadhl2h-e9944657c7ddefb3b8d2c8373c97fa47629ea1b8.tar.gz
hl2h-e9944657c7ddefb3b8d2c8373c97fa47629ea1b8.zip
Triggerbot: crosshair entity trace, hostile-only
- top-level Triggerbot feature (Active + Bind, default Mouse4, rebindable) - trace the crosshair ray from the eye with MASK_SHOT and TRACE_EVERYTHING; the filter ignores the local player - if the first entity hit is a live hostile NPC, press IN_ATTACK and fix the usercmd CRC; walls/props/friendly/neutral/corpses do not trigger - independent of Aimbot; config [triggerbot] active/bind
Diffstat (limited to '')
-rw-r--r--src/vischeck.cpp85
1 files changed, 68 insertions, 17 deletions
diff --git a/src/vischeck.cpp b/src/vischeck.cpp
index 92d194b..428f54f 100644
--- a/src/vischeck.cpp
+++ b/src/vischeck.cpp
@@ -30,9 +30,19 @@ static_assert(sizeof(VectorAlignedCompat) == 16, "VectorAligned layout");
30static_assert(offsetof(RayCompat, delta) == 16, "Ray_t delta offset"); 30static_assert(offsetof(RayCompat, delta) == 16, "Ray_t delta offset");
31static_assert(offsetof(RayCompat, isRay) == 64, "Ray_t isRay offset"); 31static_assert(offsetof(RayCompat, isRay) == 64, "Ray_t isRay offset");
32 32
33// trace_t / CBaseTrace prefix. cplane_t is Vector + float + type + signbits 33// trace_t / CGameTrace layout (Source 2013, 32-bit):
34// + 2 pad bytes, so fraction lands at 0x2C and startsolid at 0x37. 34// CBaseTrace: startpos 0, endpos 12, cplane_t plane 24 (20 bytes),
35struct TraceCompat { 35// fraction 44, contents 48, dispFlags 52, allsolid 54,
36// startsolid 55
37// CGameTrace: fractionleftsolid 56, csurface_t surface 60 (8 bytes),
38// hitgroup 68, physicsbone 72, m_pEnt 76, hitbox 80
39struct SurfaceCompat {
40 const char *name;
41 short surfaceProps;
42 unsigned short flags;
43};
44
45struct GameTraceCompat {
36 Vector startpos; 46 Vector startpos;
37 Vector endpos; 47 Vector endpos;
38 Vector normal; 48 Vector normal;
@@ -45,11 +55,18 @@ struct TraceCompat {
45 uint16_t dispFlags; 55 uint16_t dispFlags;
46 bool allsolid; 56 bool allsolid;
47 bool startsolid; 57 bool startsolid;
48 uint8_t rest[128]; // CGameTrace tail (surface, ent, hitbox, ...) 58 float fractionleftsolid;
59 SurfaceCompat surface;
60 int hitgroup;
61 short physicsbone;
62 void *ent;
63 int hitbox;
64 uint8_t rest[64]; // future-proof / avoid short writes
49}; 65};
50 66
51static_assert(offsetof(TraceCompat, fraction) == 44, "trace_t fraction"); 67static_assert(offsetof(GameTraceCompat, fraction) == 44, "trace_t fraction");
52static_assert(offsetof(TraceCompat, startsolid) == 55, "trace_t startsolid"); 68static_assert(offsetof(GameTraceCompat, startsolid) == 55, "trace_t startsolid");
69static_assert(offsetof(GameTraceCompat, ent) == 76, "trace_t m_pEnt");
53 70
54// ITraceFilter has no virtual destructor: vtable[0] = ShouldHitEntity, 71// ITraceFilter has no virtual destructor: vtable[0] = ShouldHitEntity,
55// vtable[1] = GetTraceType. 72// vtable[1] = GetTraceType.
@@ -63,9 +80,32 @@ struct WorldOnlyFilter : ITraceFilterCompat {
63 int GetTraceType() const override { return 1; } // TRACE_WORLD_ONLY 80 int GetTraceType() const override { return 1; } // TRACE_WORLD_ONLY
64}; 81};
65 82
83struct EntityFilter : ITraceFilterCompat {
84 void *ignore;
85 explicit EntityFilter(void *ig) : ignore(ig) {}
86 bool ShouldHitEntity(void *pEntity, int) override {
87 return pEntity != ignore;
88 }
89 int GetTraceType() const override { return 0; } // TRACE_EVERYTHING
90};
91
66// MASK_VISIBLE = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_OPAQUE | 92// MASK_VISIBLE = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_OPAQUE |
67// CONTENTS_IGNORE_NODRAW_OPAQUE 93// CONTENTS_IGNORE_NODRAW_OPAQUE
68constexpr unsigned MASK_VISIBLE = 0x1u | 0x4000u | 0x80u | 0x2000u; 94constexpr unsigned MASK_VISIBLE = 0x1u | 0x4000u | 0x80u | 0x2000u;
95// MASK_SHOT = SOLID|MOVEABLE|MONSTER|WINDOW|DEBRIS|HITBOX
96constexpr unsigned MASK_SHOT = 0x1u | 0x4000u | 0x2000000u | 0x4u |
97 0x4000000u | 0x40000000u;
98
99static void make_ray(RayCompat &ray, const Vector &start, const Vector &end) {
100 float dx = end.x - start.x, dy = end.y - start.y, dz = end.z - start.z;
101 ray = RayCompat{};
102 ray.start = {start.x, start.y, start.z, 0.0f};
103 ray.delta = {dx, dy, dz, 0.0f};
104 ray.startOffset = {0.0f, 0.0f, 0.0f, 0.0f};
105 ray.extents = {0.0f, 0.0f, 0.0f, 0.0f};
106 ray.isRay = true;
107 ray.isSwept = (dx * dx + dy * dy + dz * dz) > 0.0f;
108}
69 109
70} // namespace 110} // namespace
71 111
@@ -79,20 +119,31 @@ bool is_visible(const Vector &eye, const Vector &point) {
79 return true; 119 return true;
80 } 120 }
81 121
82 float dx = point.x - eye.x, dy = point.y - eye.y, dz = point.z - eye.z; 122 RayCompat ray;
83 RayCompat ray{}; 123 make_ray(ray, eye, point);
84 ray.start = {eye.x, eye.y, eye.z, 0.0f}; 124 GameTraceCompat tr{};
85 ray.delta = {dx, dy, dz, 0.0f};
86 ray.startOffset = {0.0f, 0.0f, 0.0f, 0.0f};
87 ray.extents = {0.0f, 0.0f, 0.0f, 0.0f};
88 ray.isRay = true;
89 ray.isSwept = (dx * dx + dy * dy + dz * dz) > 0.0f;
90
91 TraceCompat tr{};
92 WorldOnlyFilter filter; 125 WorldOnlyFilter filter;
93 using TraceRayFn = void (*)(void *, const RayCompat *, unsigned, void *, 126 using TraceRayFn = void (*)(void *, const RayCompat *, unsigned, void *,
94 TraceCompat *); 127 GameTraceCompat *);
95 vfunc<TraceRayFn>(g_iface.enginetrace, 4)(g_iface.enginetrace, &ray, 128 vfunc<TraceRayFn>(g_iface.enginetrace, 4)(g_iface.enginetrace, &ray,
96 MASK_VISIBLE, &filter, &tr); 129 MASK_VISIBLE, &filter, &tr);
97 return tr.fraction > 0.97f && !tr.startsolid; 130 return tr.fraction > 0.97f && !tr.startsolid;
98} 131}
132
133// Trace the crosshair ray and return the first entity hit (nullptr for world
134// or no hit). `ignore` is the local player entity pointer.
135void *trace_entity(const Vector &start, const Vector &end, void *ignore) {
136 if (!g_iface.enginetrace)
137 return nullptr;
138 RayCompat ray;
139 make_ray(ray, start, end);
140 GameTraceCompat tr{};
141 EntityFilter filter(ignore);
142 using TraceRayFn = void (*)(void *, const RayCompat *, unsigned, void *,
143 GameTraceCompat *);
144 vfunc<TraceRayFn>(g_iface.enginetrace, 4)(g_iface.enginetrace, &ray,
145 MASK_SHOT, &filter, &tr);
146 if (tr.fraction >= 1.0f || tr.startsolid)
147 return nullptr;
148 return tr.ent;
149}