S2FOW is a server-side visibility protection plugin for Counter-Strike 2.
It does one job: when a player should not be able to see an enemy, the server can stop sending that enemy to that player's game client. If the client never receives the hidden enemy, a client-side cheat has far less local player data to reveal.
This is not a ban system, not an anti-aim system, and not a sound/radar blocker. It is a practical fog-of-war layer for player visibility.
Most wallhack protection fails when the enemy data is already on the player's computer. S2FOW attacks that problem earlier.
Instead of only trusting the client, S2FOW checks visibility on the server every network frame. If an enemy is behind walls or fully blocked by smoke, S2FOW can remove that enemy's body and connected player objects from only that viewer's update.
The result is a cleaner, harder-to-abuse visibility pipeline:
| What matters | What S2FOW does |
|---|---|
| Hidden enemies | Stops sending hidden enemy player bodies to that viewer |
| Weapons and wearables | Hides them together with the player body |
| Smoke | Can hide enemies fully blocked by smoke |
| Safety | Shows players when S2FOW is unsure |
| Crash mitigation | Sends client refreshes after hide/show changes |
| Server control | Runs from the server, not from the player client |
Every network frame, S2FOW follows this flow:
- Read current players, teams, positions, movement, weapons, body size, and connected player objects.
- Skip hiding during warmup, freeze time, round end, and other moments where everyone should be visible.
- Keep recently spawned and recently dead players visible for a short grace period.
- Check smoke first. If smoke blocks every checked path to the enemy, the enemy can be hidden.
- If the viewer is already aiming close to the enemy body, show the enemy to avoid a harsh pop-in.
- Ask RayTrace whether walls block the checked body points.
- Hide the enemy only when S2FOW completed a safe check and the enemy should not be visible.
- Show the enemy whenever data is missing, RayTrace fails, or the configured raycast budget is exhausted.
That last rule is important: S2FOW is built to fail safe. When the plugin cannot prove a hide is safe, it shows the player.
What Gets Hidden
S2FOW does not only remove the player body. It also removes the connected objects that can crash a client or leak the hidden player visually.
| Object | Covered |
|---|---|
| Player body | Yes |
| Inventory weapons | Yes |
| Active weapon | Yes |
| Previous weapon used for switching animations | Yes |
| Wearables | Yes |
| Attached scene objects | Yes |
| Carried hostage objects | Yes |
| Hostage carry prop | Yes |
| Scoreboard/controller data | Left visible |
This connected-object handling is part of the crash-mitigation design. A CS2 client can fail badly if it receives a weapon, wearable, or attached object that points to a player body it never received.
S2FOW includes a full-update recovery path for the viewer whose visibility list changed.
When S2FOW hides or shows enemies for a viewer, it requests a client refresh for that viewer. Real hide/show changes are sent immediately and combined to one refresh per viewer per frame. Repeated non-critical refreshes, such as round-state refreshes, are throttled.
This requires the packaged file:
gamedata/s2fow.gamedata.json
If full-update support is unavailable, S2FOW logs the problem and pauses protection. That means all players are sent normally until the gamedata file is installed correctly. This is intentional: hiding players without the recovery refresh can cause the CopyExistingEntity: missing client entity crash.
S2FOW can hide enemies behind smoke when SmokeVisibility.HidePlayersBehindSmoke is enabled.
Smoke is modeled as a growing sphere:
- It starts smaller when it blooms.
- It grows to full size over the configured tick window.
- It stops blocking after the configured lifetime or when the engine reports the smoke expired.
- Fast pre-checking skips expensive smoke math when no smoke is near the viewer/enemy path.
Smoke hiding only happens when smoke blocks all checked paths for that enemy. A partly visible enemy is shown.
S2FOW checks real points on the CS2 player model:
- 35 model-based body and weapon points
- 8 backup box corners around the enemy
- Weapon-aware muzzle points for pistol, rifle, and sniper weapon classes
- Movement prediction for both the viewer's eyes and the enemy body
The included editor under tools/los-point-editor/ is used to inspect and tune these points. The runtime layout is generated into:
Plugin/Core/Cs2VisibilityPrimitiveLayout.cs
S2FOW is intentionally narrow. It does not claim unsupported behavior.
It does not:
- detect or ban cheaters
- hide footsteps or sound cues
- control radar or spotted-state behavior
- hide projectiles, grenades, dropped weapons, or map props
- replace server-side moderation, demos, or other anti-cheat tools
- control Source 2 PVS outside the player objects it removes from transmit
It focuses on player visibility data sent to each client.
- CounterStrikeSharp, API 276 or newer
- Metamod:Source, dev build
- Ray-Trace, with both RayTraceImpl and RayTraceApi installed
- .NET 8 for building
RayTrace is required. If RayTrace is not loaded, S2FOW stays idle and players are sent normally.
- Install Metamod:Source and CounterStrikeSharp on the server.
- Install Ray-Trace with both RayTraceImpl and RayTraceApi.
- Build S2FOW or download a release.
- Copy the release package's
addons/folder into the server'scsgo/addons/folder. - Make sure
s2fow.gamedata.jsonlands in CounterStrikeSharp's globalgamedatafolder. - Restart the server.
- Check the server console for the S2FOW startup banner and RayTrace connection message.
S2FOW generates its config automatically on first run.
dotnet build S2FOW.sln -c ReleaseBuild output:
Plugin/bin/Release/net8.0/
Drop-in server package:
Plugin/bin/Release/S2FOW-dropin/
addons/
counterstrikesharp/
gamedata/
s2fow.gamedata.json
plugins/
S2FOW/
S2FOW.dll
S2FOW.deps.json
For server installs, copy the addons folder from S2FOW-dropin into the server's csgo/addons folder. Do not put s2fow.gamedata.json inside the plugin folder; CounterStrikeSharp reads it from addons/counterstrikesharp/gamedata.
All commands require @css/root.
| Command | What it does |
|---|---|
css_s2fow_status |
Shows protection status, workload, visibility decisions, crash protection counters, and warnings |
css_fow_stats |
Same status command, kept for older admin habits |
css_s2fow_toggle |
Turns S2FOW protection on or off |
css_fow_toggle |
Same toggle command, kept for older admin habits |
When protection is disabled with the toggle command, S2FOW sends players normally and requests full updates so clients refresh cleanly.
Config files are generated here:
csgo/addons/counterstrikesharp/configs/plugins/S2FOW/
S2FOW writes a guided JSON config with plain-English comments. Current config schema: 33.
Old v32 config files still load. S2FOW reads the old names once, then rewrites the file with the current plain-English names.
| Section | Plain meaning |
|---|---|
Main |
Main on/off behavior, death grace, and round-start visibility |
SmokeVisibility |
Smoke hiding, smoke size, smoke lifetime, and smoke growth |
EnemyCheckPoints |
Enemy body checks, distance rules, view-angle rules, and enemy movement prediction |
ViewerEyePrediction |
Small viewer eye prediction for fast movement and jumps |
Debug |
Optional HUD, ray lines, and body-point drawings |
Advanced |
Raycast budget, smoke pre-checking, box padding, aim reveal, and eye height offset |
Common settings:
| Setting | Default | Meaning |
|---|---|---|
Main.ProtectionEnabled |
true |
Main protection switch |
Main.KeepDeadPlayersVisibleTicks |
128 |
Keeps killed players visible briefly, about 2 seconds on 64 tick |
Main.ShowEveryoneAtRoundStartTicks |
32 |
Shows everyone briefly when live play starts, about 0.5 seconds on 64 tick |
SmokeVisibility.HidePlayersBehindSmoke |
true |
Allows smoke to hide enemies |
SmokeVisibility.SmokeSizeUnits |
130.0 |
Approximate smoke blocking size in Source 2 units |
SmokeVisibility.SmokeLastsTicks |
1232 |
Smoke blocking lifetime, about 19.25 seconds on 64 tick |
SmokeVisibility.SmokeGrowsTicks |
192 |
Smoke growth time, about 3 seconds on 64 tick |
EnemyCheckPoints.UseFewerChecksFarAway |
true |
Uses lighter checks for far enemies |
EnemyCheckPoints.UseFewerChecksOutsideView |
false |
Optional lighter checks outside the viewer's aim direction |
Advanced.RaycastLimitPerFrame |
0 |
0 means unlimited raycasts, which avoids delayed visibility decisions |
Advanced.FastSmokePreCheck |
true |
Skips detailed smoke checks when smoke is nowhere near the viewer/enemy path |
Debug.ShowDebugHud |
false |
Shows the in-game S2FOW debug HUD |
Debug.ShowDebugRays |
false |
Draws the wall checks S2FOW sends to RayTrace |
Debug.ShowDebugPoints |
false |
Draws the enemy body points S2FOW checks |
The old RayHitFractionThreshold and RayHitDistanceThreshold settings are no longer written. Current visibility behavior is strict: any world hit before the checked enemy point blocks that path.
Use:
css_s2fow_status
The status output is grouped for server owners:
Status: protection on/off, RayTrace readiness, round state, config schemaWork: player checks, raycasts, average plugin time, average raycasts, peak raycastsVisibility decisions: smoke hides, blocked-sight hides, safe-show fallbacksCrash protection: full updates sent, throttled, failed, requested, and combinedWarnings: config write failures, player-object read failures, incomplete child collection, RayTrace failures
Debug mode is for testing, not normal public play.
When enabled, S2FOW can draw:
- a small HUD with labels like
Enemies checked,Raycasts, andWhy shown/hidden - yellow ray lines for clear checks
- blue ray lines for blocked checks
- white body points and blue backup box points around enemies
These debug drawings create real game objects, so keep them off during normal matches.
Plugin/
S2FOWPlugin.cs Plugin identity, shared fields, reading guide
S2FOWPlugin.Lifecycle.cs Loading, unloading, config setup, RayTrace connection
S2FOWPlugin.Transmit.cs Per-viewer player hiding in CheckTransmit
S2FOWPlugin.Events.cs Match events: spawn, death, smoke, bomb, map changes
S2FOWPlugin.FullUpdate.cs Viewer refresh queue and crash-recovery updates
S2FOWPlugin.Commands.cs Admin commands
S2FOWPlugin.Debug.cs Startup banner, status text, debug HUD
Config/ Config schema and guided config writer
Core/ Visibility decisions, ray checks, snapshots, smoke, full update bridge
Models/ Player snapshots, smoke data, debug drawing data
Util/ Text, diagnostics, performance counters, vector math
gamedata/
s2fow.gamedata.json Source copy for package building; installs to addons/counterstrikesharp/gamedata
tools/
los-point-editor/ Browser editor for visibility points
apply_los_points_to_layout.py
extract_cs2_visibility_primitives.py
- Install dependencies first: CounterStrikeSharp, Metamod:Source, and Ray-Trace.
- Install S2FOW from the drop-in package so the plugin and gamedata land in the right folders.
- Start the server and confirm RayTrace connects.
- Leave defaults on the first test.
- Use
css_s2fow_statusto watch workload and warnings. - Enable debug drawings only on a private test server.
- Tune config only if your server has a specific visibility or performance issue.
S2FOW is licensed under AGPLv3.

