Server-side ESP/wallhack protection: hides enemies from a client's packet unless there is a real line of sight.
csb_wallhack_blocker.sma v1.0.0
1
/*
2
* CSB Wallhack Blocker
3
* Copyright (C) 2026 counter-strike-boost.com
4
*
5
* Server-side wallhack / ESP protection. In FM_AddToFullPack the plugin decides,
6
* per viewer, whether an enemy player entity is actually visible: it must be in
7
* the viewer's PVS and have a clear line of sight from the viewer's eyes to the
8
* target's centre or head. If neither is clear (and the target has not fired
9
* recently), the entity is dropped from that client's packet, so it cannot be
10
* seen through walls. Teammates and recently-firing enemies are always shown.
11
*
12
* Inspired by the classic AddToFullPack wall blocker approach (Fysiks /
13
* OrangeBox). Independent GPL re-implementation; no original code is reused.
14
*
15
* This program is free software: you can redistribute it and/or modify it under
16
* the terms of the GNU General Public License as published by the Free Software
17
* Foundation, either version 3 of the License, or (at your option) any later
18
* version. It is distributed in the hope that it will be useful, but WITHOUT
19
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20
* FOR A PARTICULAR PURPOSE. See <https://www.gnu.org/licenses/> for details.
21
*/
22
23
#include <amxmodx>
24
#include <fakemeta>
25
26
new const PLUGIN[] = "CSB Wallhack Blocker"
27
new const VERSION[] = "1.0.0"
28
new const AUTHOR[] = "counter-strike-boost.com"
29
30
new g_pEnabled, g_pGrace
31
new Float:g_fLastFire[33]
32
new g_iMaxPlayers
33
34
public plugin_init()
35
{
36
register_plugin(PLUGIN, VERSION, AUTHOR)
37
38
g_pEnabled = register_cvar("csb_wh_enabled", "1")
39
g_pGrace = register_cvar("csb_wh_firegrace", "1.2")
40
41
register_forward(FM_AddToFullPack, "fwAddToFullPack", 0)
42
register_forward(FM_EmitSound, "fwEmitSound", 0)
43
44
g_iMaxPlayers = get_maxplayers()
45
}
46
47
public client_putinserver(id)
48
{
49
g_fLastFire[id] = 0.0
50
}
51
52
/* record when a player produces a weapon sound, for the fire grace window */
53
public fwEmitSound(ent, channel, const sample[])
54
{
55
if (ent >= 1 && ent <= g_iMaxPlayers)
56
{
57
if (sample[0] == 'w' && sample[1] == 'e' && containi(sample, "weapons/") == 0)
58
g_fLastFire[ent] = get_gametime()
59
}
60
61
return FMRES_IGNORED
62
}
63
64
public fwAddToFullPack(es, e, ent, host, hostflags, player, pSet)
65
{
66
if (!get_pcvar_num(g_pEnabled))
67
return FMRES_IGNORED
68
69
/* only care about player entities being packed for a player host */
70
if (!player)
71
return FMRES_IGNORED
72
73
if (ent < 1 || ent > g_iMaxPlayers || host < 1 || host > g_iMaxPlayers)
74
return FMRES_IGNORED
75
76
if (ent == host)
77
return FMRES_IGNORED
78
79
if (!is_user_alive(host) || !is_user_alive(ent))
80
return FMRES_IGNORED
81
82
/* never hide teammates */
83
if (get_user_team(host) == get_user_team(ent))
84
return FMRES_IGNORED
85
86
/* recently fired -> position is already given away, keep visible */
87
if (get_gametime() - g_fLastFire[ent] < get_pcvar_float(g_pGrace))
88
return FMRES_IGNORED
89
90
/* must be inside the host PVS at all */
91
if (!engfunc(EngFunc_CheckVisibility, ent, pSet))
92
return FMRES_SUPERCEDE
93
94
/* eye position of the viewer */
95
static Float:fEye[3], Float:fOfs[3]
96
pev(host, pev_origin, fEye)
97
pev(host, pev_view_ofs, fOfs)
98
fEye[0] += fOfs[0]
99
fEye[1] += fOfs[1]
100
fEye[2] += fOfs[2]
101
102
/* target centre and head */
103
static Float:fTarget[3], Float:fHead[3], Float:fTOfs[3]
104
pev(ent, pev_origin, fTarget)
105
pev(ent, pev_view_ofs, fTOfs)
106
107
fHead[0] = fTarget[0] + fTOfs[0]
108
fHead[1] = fTarget[1] + fTOfs[1]
109
fHead[2] = fTarget[2] + fTOfs[2]
110
111
if (clearLine(fEye, fTarget, host) || clearLine(fEye, fHead, host))
112
return FMRES_IGNORED
113
114
/* no clear sight line -> drop from this client's packet */
115
return FMRES_SUPERCEDE
116
}
117
118
bool:clearLine(const Float:start[3], const Float:end[3], ignore)
119
{
120
engfunc(EngFunc_TraceLine, start, end, IGNORE_MONSTERS, ignore, 0)
121
122
static Float:fFrac
123
get_tr2(0, TR_flFraction, fFrac)
124
125
return (fFrac >= 1.0)
126
}
127









