From e9944657c7ddefb3b8d2c8373c97fa47629ea1b8 Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 26 Oct 2026 17:22:25 +0100 Subject: 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 --- src/vischeck.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 17 deletions(-) (limited to 'src/vischeck.cpp') 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"); static_assert(offsetof(RayCompat, delta) == 16, "Ray_t delta offset"); static_assert(offsetof(RayCompat, isRay) == 64, "Ray_t isRay offset"); -// trace_t / CBaseTrace prefix. cplane_t is Vector + float + type + signbits -// + 2 pad bytes, so fraction lands at 0x2C and startsolid at 0x37. -struct TraceCompat { +// trace_t / CGameTrace layout (Source 2013, 32-bit): +// CBaseTrace: startpos 0, endpos 12, cplane_t plane 24 (20 bytes), +// fraction 44, contents 48, dispFlags 52, allsolid 54, +// startsolid 55 +// CGameTrace: fractionleftsolid 56, csurface_t surface 60 (8 bytes), +// hitgroup 68, physicsbone 72, m_pEnt 76, hitbox 80 +struct SurfaceCompat { + const char *name; + short surfaceProps; + unsigned short flags; +}; + +struct GameTraceCompat { Vector startpos; Vector endpos; Vector normal; @@ -45,11 +55,18 @@ struct TraceCompat { uint16_t dispFlags; bool allsolid; bool startsolid; - uint8_t rest[128]; // CGameTrace tail (surface, ent, hitbox, ...) + float fractionleftsolid; + SurfaceCompat surface; + int hitgroup; + short physicsbone; + void *ent; + int hitbox; + uint8_t rest[64]; // future-proof / avoid short writes }; -static_assert(offsetof(TraceCompat, fraction) == 44, "trace_t fraction"); -static_assert(offsetof(TraceCompat, startsolid) == 55, "trace_t startsolid"); +static_assert(offsetof(GameTraceCompat, fraction) == 44, "trace_t fraction"); +static_assert(offsetof(GameTraceCompat, startsolid) == 55, "trace_t startsolid"); +static_assert(offsetof(GameTraceCompat, ent) == 76, "trace_t m_pEnt"); // ITraceFilter has no virtual destructor: vtable[0] = ShouldHitEntity, // vtable[1] = GetTraceType. @@ -63,9 +80,32 @@ struct WorldOnlyFilter : ITraceFilterCompat { int GetTraceType() const override { return 1; } // TRACE_WORLD_ONLY }; +struct EntityFilter : ITraceFilterCompat { + void *ignore; + explicit EntityFilter(void *ig) : ignore(ig) {} + bool ShouldHitEntity(void *pEntity, int) override { + return pEntity != ignore; + } + int GetTraceType() const override { return 0; } // TRACE_EVERYTHING +}; + // MASK_VISIBLE = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_OPAQUE | // CONTENTS_IGNORE_NODRAW_OPAQUE constexpr unsigned MASK_VISIBLE = 0x1u | 0x4000u | 0x80u | 0x2000u; +// MASK_SHOT = SOLID|MOVEABLE|MONSTER|WINDOW|DEBRIS|HITBOX +constexpr unsigned MASK_SHOT = 0x1u | 0x4000u | 0x2000000u | 0x4u | + 0x4000000u | 0x40000000u; + +static void make_ray(RayCompat &ray, const Vector &start, const Vector &end) { + float dx = end.x - start.x, dy = end.y - start.y, dz = end.z - start.z; + ray = RayCompat{}; + ray.start = {start.x, start.y, start.z, 0.0f}; + ray.delta = {dx, dy, dz, 0.0f}; + ray.startOffset = {0.0f, 0.0f, 0.0f, 0.0f}; + ray.extents = {0.0f, 0.0f, 0.0f, 0.0f}; + ray.isRay = true; + ray.isSwept = (dx * dx + dy * dy + dz * dz) > 0.0f; +} } // namespace @@ -79,20 +119,31 @@ bool is_visible(const Vector &eye, const Vector &point) { return true; } - float dx = point.x - eye.x, dy = point.y - eye.y, dz = point.z - eye.z; - RayCompat ray{}; - ray.start = {eye.x, eye.y, eye.z, 0.0f}; - ray.delta = {dx, dy, dz, 0.0f}; - ray.startOffset = {0.0f, 0.0f, 0.0f, 0.0f}; - ray.extents = {0.0f, 0.0f, 0.0f, 0.0f}; - ray.isRay = true; - ray.isSwept = (dx * dx + dy * dy + dz * dz) > 0.0f; - - TraceCompat tr{}; + RayCompat ray; + make_ray(ray, eye, point); + GameTraceCompat tr{}; WorldOnlyFilter filter; using TraceRayFn = void (*)(void *, const RayCompat *, unsigned, void *, - TraceCompat *); + GameTraceCompat *); vfunc(g_iface.enginetrace, 4)(g_iface.enginetrace, &ray, MASK_VISIBLE, &filter, &tr); return tr.fraction > 0.97f && !tr.startsolid; } + +// Trace the crosshair ray and return the first entity hit (nullptr for world +// or no hit). `ignore` is the local player entity pointer. +void *trace_entity(const Vector &start, const Vector &end, void *ignore) { + if (!g_iface.enginetrace) + return nullptr; + RayCompat ray; + make_ray(ray, start, end); + GameTraceCompat tr{}; + EntityFilter filter(ignore); + using TraceRayFn = void (*)(void *, const RayCompat *, unsigned, void *, + GameTraceCompat *); + vfunc(g_iface.enginetrace, 4)(g_iface.enginetrace, &ray, + MASK_SHOT, &filter, &tr); + if (tr.fraction >= 1.0f || tr.startsolid) + return nullptr; + return tr.ent; +} -- cgit v1.2.3