1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
// vischeck.cpp — world-only line-of-sight test via EngineTraceClient003.
//
// IEngineTrace::TraceRay (vtable slot 4) is given a ray from the eye to the
// aim point and a TRACE_WORLD_ONLY filter. MASK_VISIBLE ignores glass/windows
// (you can see through them) while still hitting opaque world geometry.
// Per the SDK, TRACE_WORLD_ONLY does not test static props; that is the
// deliberate trade-off for this build.
#include "hl2h.h"
#include <cstddef>
#include <cstdint>
namespace {
struct alignas(16) VectorAlignedCompat {
float x, y, z, w;
};
// Ray_t: four VectorAligned (16 bytes each) followed by two bools.
struct alignas(16) RayCompat {
VectorAlignedCompat start;
VectorAlignedCompat delta;
VectorAlignedCompat startOffset;
VectorAlignedCompat extents;
bool isRay;
bool isSwept;
};
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 {
Vector startpos;
Vector endpos;
Vector normal;
float dist;
uint8_t type;
uint8_t signbits;
uint8_t pad[2];
float fraction;
int contents;
uint16_t dispFlags;
bool allsolid;
bool startsolid;
uint8_t rest[128]; // CGameTrace tail (surface, ent, hitbox, ...)
};
static_assert(offsetof(TraceCompat, fraction) == 44, "trace_t fraction");
static_assert(offsetof(TraceCompat, startsolid) == 55, "trace_t startsolid");
// ITraceFilter has no virtual destructor: vtable[0] = ShouldHitEntity,
// vtable[1] = GetTraceType.
struct ITraceFilterCompat {
virtual bool ShouldHitEntity(void *pEntity, int contentsMask) = 0;
virtual int GetTraceType() const = 0;
};
struct WorldOnlyFilter : ITraceFilterCompat {
bool ShouldHitEntity(void *, int) override { return false; }
int GetTraceType() const override { return 1; } // TRACE_WORLD_ONLY
};
// MASK_VISIBLE = CONTENTS_SOLID | CONTENTS_MOVEABLE | CONTENTS_OPAQUE |
// CONTENTS_IGNORE_NODRAW_OPAQUE
constexpr unsigned MASK_VISIBLE = 0x1u | 0x4000u | 0x80u | 0x2000u;
} // namespace
bool is_visible(const Vector &eye, const Vector &point) {
static bool warned = false;
if (!g_iface.enginetrace) {
if (!warned) {
warned = true;
logf("vischeck: EngineTraceClient003 unavailable; failing open");
}
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{};
WorldOnlyFilter filter;
using TraceRayFn = void (*)(void *, const RayCompat *, unsigned, void *,
TraceCompat *);
vfunc<TraceRayFn>(g_iface.enginetrace, 4)(g_iface.enginetrace, &ray,
MASK_VISIBLE, &filter, &tr);
return tr.fraction > 0.97f && !tr.startsolid;
}
|