Add 6 tutorials (6 files)
Browse Source
6 changed files
with 316 additions and 0 deletions
A
anti-flood-chat-settings/en.md
+50 -0
A
cs16-black-screen-launch/en.md
+9 -0
A
cs16-fps-max-explained/en.md
+55 -0
A
how-many-slots-server/en.md
+63 -0
A
restrict-client-cvars/en.md
+87 -0
A
spot-backdoored-amxx-plugin/en.md
+52 -0
anti-flood-chat-settings/en.md
A
| @@ -0,0 +1,50 @@ | ||
| 1 | +--- | |
| 2 | +title: "Anti-Flood and Anti-Spam Chat Settings" | |
| 3 | +excerpt: "How AMX Mod X flood control works with amx_flood_time, how to curb spray and command spam, and when to move from cvars to a dedicated anti-flood plugin." | |
| 4 | +category: "administration" | |
| 5 | +tags: "chat, moderation" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>Chat flooding — the same player pasting a line of text on a bind, over and over, until the chat is unreadable — is one of the most common nuisances on a public CS 1.6 server. AMX Mod X has built-in flood control that handles the ordinary case with a single cvar, and there are a couple of engine settings that curb the related spam of sprays and decals. Here is how to tune all of it, and where the built-in limits stop being enough.</p> | |
| 10 | + | |
| 11 | +<h2>1. The built-in flood control</h2> | |
| 12 | +<p>A default AMX Mod X install loads <code>antiflood.amxx</code>, which throttles how fast a single client can send chat messages. It is controlled by one cvar in <a href="/tutorials/amxx-cfg-explained">amxx.cfg</a>:</p> | |
| 13 | +<pre>amx_flood_time 0.75</pre> | |
| 14 | +<p>This is the minimum number of seconds that must pass between one player's chat messages. Send messages faster than that and the plugin blocks the excess and warns the player. The trade-off is direct: lower the value and more spam gets through; raise it too far and legitimate rapid chat during a firefight gets swallowed. <code>0.75</code> is a sensible balance for most public servers; a heavily trafficked server prone to spam might go to <code>1.0</code>.</p> | |
| 15 | + | |
| 16 | +<h2>2. Confirm the plugin is actually loaded</h2> | |
| 17 | +<p>The cvar does nothing if the plugin behind it is disabled. Check:</p> | |
| 18 | +<pre>amxx plugins</pre> | |
| 19 | +<p>Look for <code>antiflood.amxx</code> reading <code>running</code>. If it is commented out in <a href="/tutorials/plugins-ini-load-order">plugins.ini</a>, <code>amx_flood_time</code> is inert no matter what you set it to. Re-enable the line and change the map.</p> | |
| 20 | + | |
| 21 | +<h2>3. Curb spray and decal spam</h2> | |
| 22 | +<p>Spray flooding is separate from chat and is handled by an engine cvar, not AMXX. <code>decalfrequency</code> sets the minimum seconds between a player's sprays:</p> | |
| 23 | +<pre>decalfrequency 30</pre> | |
| 24 | +<p>The default is low enough that a determined player can wallpaper a wall. Raising it to <code>30</code> or <code>60</code> forces a cooldown between sprays. Put this in <a href="/tutorials/setup-server-cfg-cs16">server.cfg</a> alongside your other core cvars.</p> | |
| 25 | + | |
| 26 | +<h2>4. Voice and command spam</h2> | |
| 27 | +<p>Chat is only one channel. A player can also spam:</p> | |
| 28 | +<ul> | |
| 29 | +<li><strong>Voice</strong> — a screaming mic is not chat flood and <code>amx_flood_time</code> does nothing to it. Silence it with a <a href="/tutorials/amx-gag-mute-players">voice gag</a>.</li> | |
| 30 | +<li><strong>Commands and menus</strong> — rapid-fire menu opening or command binds. The built-in flood control targets <code>say</code>/<code>say_team</code>, not arbitrary client commands, so command spam needs a plugin that rate-limits those specifically.</li> | |
| 31 | +</ul> | |
| 32 | +<p>Recognising which channel is being abused tells you which tool to reach for — the chat cvar only fixes chat. A player who has been chat-limited will often just switch to spamming their microphone or opening a menu on a bind, so keep the whole picture in mind rather than assuming <code>amx_flood_time</code> covers every kind of spam.</p> | |
| 33 | + | |
| 34 | +<h2>5. When to move to a dedicated plugin</h2> | |
| 35 | +<p>The stock <code>amx_flood_time</code> is a single blunt threshold. If your server attracts persistent spammers, a dedicated <a href="/plugins/csb-anti-flood">anti-flood plugin</a> gives you finer control: per-message repeat detection (blocking the same line pasted twice), escalating penalties, separate limits for chat versus team-chat, and automatic gagging of repeat offenders so you are not moderating by hand. That is the point where you graduate from a cvar to a plugin. For individual offenders who ignore the automatic limits, fall back to a manual <a href="/tutorials/amx-gag-mute-players">gag</a> or, ultimately, a <a href="/tutorials/amx-slap-slay-kick">kick</a>.</p> | |
| 36 | + | |
| 37 | +<h2>Common errors</h2> | |
| 38 | +<ul> | |
| 39 | +<li><strong><code>amx_flood_time</code> has no effect</strong> — <code>antiflood.amxx</code> is not loaded. Confirm with <code>amxx plugins</code> and re-enable it in <code>plugins.ini</code>.</li> | |
| 40 | +<li><strong>Normal fast chat gets blocked</strong> — the value is too high. Lower it toward <code>0.5</code>–<code>0.75</code>.</li> | |
| 41 | +<li><strong>Spam still gets through</strong> — the offender is pasting slower than the threshold, or is spamming voice/commands rather than <code>say</code>. Match the tool to the channel; consider a plugin with repeat-line detection.</li> | |
| 42 | +<li><strong>Sprays still spam despite the setting</strong> — <code>decalfrequency</code> was set but the config that holds it is not executing, or a plugin overrides it later. Confirm the value in the console.</li> | |
| 43 | +<li><strong>Setting reverts after a map change</strong> — a per-map config or a plugin re-sets the cvar after <code>amxx.cfg</code>. Trace the execution order.</li> | |
| 44 | +</ul> | |
| 45 | + | |
| 46 | +<h2>Verification</h2> | |
| 47 | +<p>Read the cvars back in the console to confirm they took:</p> | |
| 48 | +<pre>amx_flood_time | |
| 49 | +decalfrequency</pre> | |
| 50 | +<p>Then test the behaviour directly: bind a key to spam <code>say test</code> and confirm messages sent faster than <code>amx_flood_time</code> are blocked with a warning. Spray twice in quick succession and confirm the second is refused until <code>decalfrequency</code> elapses. If the limits hold but a specific player keeps finding ways around them, move to a <a href="/plugins/csb-anti-flood">dedicated anti-flood plugin</a> with repeat detection and automatic penalties.</p> |
cs16-black-screen-launch/en.md
A
| @@ -0,0 +1,9 @@ | ||
| 1 | +--- | |
| 2 | +title: "Fix: CS 1.6 Black Screen on Launch" | |
| 3 | +excerpt: "Why CS 1.6 launches to a black screen, forcing a safe windowed mode and resolution from launch options, resetting a bad video config, and the 25th Anniversary update rollback." | |
| 4 | +category: "client" | |
| 5 | +tags: "crash, video" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>CS 1.6 starts, the music plays, but the screen is black — or it opens on a monitor that shows nothing while the process is clearly running. This is almost always a video-mode problem: the game is trying to use a resolution or renderer your display cannot present in full-screen. The fixes are all about forcing it into a mode you know works, then setting a sane resolution from there.</p><h2>1. Force a safe windowed mode</h2><p>The fastest diagnostic and fix is to stop the game grabbing full-screen at a bad resolution. In Steam, right-click CS → Properties → Set Launch Options and enter:</p><pre>-window -w 640 -h 480</pre><p><code>-window</code> runs it in a window on your desktop, and <code>-w 640 -h 480</code> forces a resolution every display can show. If the game now opens in a small window, the black screen was a full-screen resolution mismatch. From here, go to Options → Video, pick a resolution your monitor supports, then remove <code>-window</code> if you want full-screen back.</p><h2>2. Try the software renderer to rule out OpenGL</h2><p>If windowed mode still shows black, force the software renderer to isolate the graphics API:</p><pre>-sw -w 640 -h 480</pre><p><code>-sw</code> uses software rendering, which sidesteps a broken or unsupported OpenGL path. If the game appears in software but not in OpenGL, the problem is your GPU driver or the OpenGL mode — update the driver, then switch back to OpenGL (<code>-gl</code>) at a supported resolution. Software mode looks worse and is only a diagnostic step, not where you should stay.</p><h2>3. Reset a poisoned video config</h2><p>A bad resolution saved in <code>config.cfg</code> makes the game reload the same broken mode every launch. Reset it:</p><ul><li>Navigate to <code>Steam/steamapps/common/Half-Life/cstrike/</code>.</li><li>Rename <code>config.cfg</code> to <code>config.cfg.bak</code> (keep it — it has your binds).</li><li>Launch with <code>-window -w 640 -h 480</code>; the game recreates a fresh <code>config.cfg</code> at a safe resolution.</li></ul><p>Once it launches cleanly you can copy your binds and rates back out of the <code>.bak</code> into a fresh <a href="/tutorials/cs16-autoexec-cfg">autoexec.cfg</a> rather than restoring the whole broken file. This also clears a bad <code>gl_</code> or <code>vid_</code> setting that a guide told you to paste in.</p><h2>4. Verify the game files</h2><p>A black screen can be a missing or corrupt engine file. In Steam, right-click CS → Properties → Installed Files → <strong>Verify integrity of game files</strong>. Steam re-downloads anything corrupted. Do this before assuming it is a settings problem, especially if the game crashed or was force-closed during an update.</p><h2>5. The 25th Anniversary update rollback</h2><p>The 2023 25th Anniversary update to Counter-Strike changed the engine and broke launch on some older setups — black screens, crashes, and mods that no longer loaded. Valve provides a legacy branch to roll back to the pre-update build. In Steam, right-click CS → Properties → Betas, and select the <code>steam_legacy</code> branch from the dropdown; Steam downloads the older build. If your black screen started right after that update and nothing above fixed it, the legacy branch is the reliable escape. This is the same rollback server admins use when the update breaks compatibility on the server side.</p><h2>6. Order the fixes by likelihood</h2><p>Work through these in order rather than pasting random launch options from a forum, because each one both fixes and diagnoses. Start with <code>-window -w 640 -h 480</code>: if the window opens, you have proven it was a full-screen resolution mismatch and you fix it from Options → Video. If that still fails, add <code>-sw</code> to prove whether OpenGL is the culprit — software mode working points squarely at your GPU driver. Only if both windowed modes fail do you touch the config, because renaming <code>config.cfg</code> throws away a good file for no reason if the real problem was the renderer. Verify game files before blaming settings if the game was ever force-closed mid-update. And keep the <code>steam_legacy</code> rollback as the last resort, since it reverts you to an older build with its own trade-offs. Piling every flag into the launch line at once tells you nothing about which one mattered.</p><h2>Common errors</h2><ul><li><strong>Black screen but music plays</strong> — full-screen resolution mismatch. Launch with <code>-window -w 640 -h 480</code>, then set a supported resolution.</li><li><strong>Still black in windowed OpenGL</strong> — a GPU/driver or OpenGL issue. Try <code>-sw</code> to confirm, then update the graphics driver.</li><li><strong>Reverts to black every launch</strong> — a bad resolution is saved in <code>config.cfg</code>. Rename it and let the game regenerate one.</li><li><strong>Opens on the wrong monitor / off-screen</strong> — use <code>-window</code> to grab it, drag it to the correct display, then reconfigure.</li><li><strong>Started after the Anniversary update</strong> — roll back via the <code>steam_legacy</code> beta branch.</li><li><strong>Alt-tab shows a black game but a working desktop</strong> — exclusive full-screen failed to present; <code>-noborder</code> borderless windowed at your desktop resolution often works around it.</li></ul><h2>Verification</h2><p>After applying a fix, launch and confirm you reach the main menu. Then set your real resolution in Options → Video, exit to desktop, and relaunch to confirm it opens correctly with those settings saved — if it goes black again, the config did not save a good mode and you should reset it as in step 3. Once the game launches reliably at your chosen resolution, tune the display with the <a href="/tutorials/cs16-black-bars-aspect-ratio">aspect-ratio and black-bars guide</a>.</p> |
cs16-fps-max-explained/en.md
A
| @@ -0,0 +1,55 @@ | ||
| 1 | +--- | |
| 2 | +title: "fps_max and fps_override in CS 1.6: The Truth" | |
| 3 | +excerpt: "How fps_max really works in CS 1.6, why it is capped at 100 until you set fps_override, how FPS affects bunnyhopping physics, and how to lock a stable frame rate." | |
| 4 | +category: "client" | |
| 5 | +tags: "fps, cvars" | |
| 6 | +image: "" | |
| 7 | +read_time: "7 min read" | |
| 8 | +--- | |
| 9 | +<p>Frame rate in CS 1.6 is tangled up with movement physics, which is why the community obsesses over specific numbers like 100 or 250 FPS. There is a lot of half-true advice floating around. This lays out what <code>fps_max</code> actually does, why <code>fps_override</code> exists, how the frame rate feeds into movement, and how to pick and lock a value that is stable.</p> | |
| 10 | + | |
| 11 | +<h2>1. What fps_max does</h2> | |
| 12 | +<p><code>fps_max</code> is your client's frame-rate ceiling — the game will not render more frames per second than this value:</p> | |
| 13 | +<pre>fps_max 100</pre> | |
| 14 | +<p>By default the engine will not let <code>fps_max</code> take effect above <strong>100</strong>. Set <code>fps_max 300</code> on a stock client and you are still capped at 100. That cap is the source of most confusion: people set a big number, see 100 in the FPS meter, and assume their hardware is the limit when it is the engine.</p> | |
| 15 | + | |
| 16 | +<h2>2. What fps_override unlocks</h2> | |
| 17 | +<p>To raise the ceiling past 100 you must first flip the override:</p> | |
| 18 | +<pre>fps_override 1 | |
| 19 | +fps_max 300</pre> | |
| 20 | +<p>With <code>fps_override 1</code> the engine honours higher <code>fps_max</code> values (up to the engine's own hard ceiling, 1000). Without it, the second line is ignored. So the true unlock is two cvars, in this order: override on, then the cap. If your FPS refuses to go above 100 no matter what you type, you forgot <code>fps_override 1</code>.</p> | |
| 21 | + | |
| 22 | +<h2>3. Why the number affects movement</h2> | |
| 23 | +<p>This is the part that makes FPS more than a smoothness setting. The Half-Life engine ties some movement mechanics to the frame rate, so different <code>fps_max</code> values produce subtly different physics. The practical upshots players care about:</p> | |
| 24 | +<ul> | |
| 25 | +<li>Certain FPS values make <strong>bunnyhopping</strong> and strafe acceleration easier or more consistent, which is why some players lock to specific numbers.</li> | |
| 26 | +<li>Very high, unstable frame rates can make movement feel <em>less</em> consistent than a rock-steady lower number.</li> | |
| 27 | +</ul> | |
| 28 | +<p>The lesson is that a <strong>stable</strong> frame rate matters more than a big one. A steady 100 beats a jittery 300 that dips constantly.</p> | |
| 29 | + | |
| 30 | +<h2>4. Pick a value your hardware holds</h2> | |
| 31 | +<p>Choose the highest number your machine can sustain without dipping, not the highest it can momentarily touch. If your FPS bounces around, cap it below your worst-case rather than at your peak:</p> | |
| 32 | +<pre>fps_override 1 | |
| 33 | +fps_max 144 // or match your monitor's refresh</pre> | |
| 34 | +<p>Matching <code>fps_max</code> to your monitor's refresh (set with the <code>-freq</code> launch option, covered in the <a href="/tutorials/cs16-competitive-video-config">video config</a>) keeps tearing down and frame delivery even. Chasing four-digit frame rates for their own sake is mostly pointless on this engine — past the point where your monitor and your movement feel smooth, extra frames buy you nothing but heat and noise, and if they come at the cost of stability they actively hurt.</p> | |
| 35 | + | |
| 36 | +<h2>5. Measure it, do not guess</h2> | |
| 37 | +<p>Turn on a live readout so you are tuning against real numbers:</p> | |
| 38 | +<pre>cl_showfps 1 // simple FPS counter | |
| 39 | +net_graph 3 // FPS plus choke, loss and ping</pre> | |
| 40 | +<p><code>net_graph 3</code> is the better tool because it also shows <strong>choke</strong> and <strong>loss</strong> — if those spike, your problem is the network or your rates, not frame rate. Rates are covered in the <a href="/tutorials/essential-server-cvars">server cvars</a> reference. Save your FPS cvars in <code>autoexec.cfg</code> so they load every launch.</p> | |
| 41 | + | |
| 42 | +<h2>Common errors</h2> | |
| 43 | +<ul> | |
| 44 | +<li><strong>FPS stuck at 100 no matter the value</strong> — you set <code>fps_max</code> high but not <code>fps_override 1</code>. Set the override first.</li> | |
| 45 | +<li><strong>Movement feels inconsistent at high FPS</strong> — the frame rate is unstable and dipping. Cap at a number you can hold steadily instead of your peak.</li> | |
| 46 | +<li><strong>Screen tearing</strong> — <code>fps_max</code> far above your refresh rate. Match it to the monitor and set <code>-freq</code>.</li> | |
| 47 | +<li><strong>High FPS but the game still stutters</strong> — that is choke/loss, not frame rate. Check <code>net_graph 3</code> and fix your rates.</li> | |
| 48 | +<li><strong>Settings reset each launch</strong> — you typed them in console or put them in <code>config.cfg</code>. Move them to <code>autoexec.cfg</code>.</li> | |
| 49 | +</ul> | |
| 50 | + | |
| 51 | +<h2>Verification</h2> | |
| 52 | +<p>Turn on the counter and confirm your cap holds under load — join a busy server, not an empty one, because that is where FPS actually drops:</p> | |
| 53 | +<pre>cl_showfps 1 | |
| 54 | +fps_max</pre> | |
| 55 | +<p>Typing <code>fps_max</code> with no value echoes the current cap; the on-screen counter should sit at or just under it with only small dips. If it is pinned at 100 despite a higher cap, <code>fps_override</code> is still 0 — set it to 1 and re-check. Once the number is high and, more importantly, <em>steady</em>, your movement will feel consistent, which is the real point of tuning FPS at all.</p> |
how-many-slots-server/en.md
A
| @@ -0,0 +1,63 @@ | ||
| 1 | +--- | |
| 2 | +title: "How Many Slots Should Your Server Have? (16, 20 or 32)" | |
| 3 | +excerpt: "Slot count is a gameplay and resource decision, not a bragging number: how maxplayers interacts with map size, bandwidth and server FPS, and sensible counts for classic, popular and fun modes." | |
| 4 | +category: "administration" | |
| 5 | +tags: "slots, planning" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>\"How many slots?\" looks like a vanity question and is actually a design decision that touches gameplay, bandwidth, and CPU all at once. A 32-slot server on <code>de_dust2</code> is chaos; a 12-slot zombie server dies of boredom. CS 1.6 caps you at 32, but the right number is almost always lower than the maximum, and picking it well is the difference between a server that feels good and one that feels like a scrum. Here is how to reason about it.</p> | |
| 10 | + | |
| 11 | +<h2>1. How the slot count is set</h2> | |
| 12 | +<p>Maximum players is fixed at launch, not in <code>server.cfg</code>. It is the <code>maxplayers</code> value on the command line (or <code>+maxplayers</code>), and it cannot exceed 32:</p> | |
| 13 | +<pre>./hlds_run -game cstrike +ip 0.0.0.0 -port 27015 \ | |
| 14 | + +map de_dust2 +maxplayers 20</pre> | |
| 15 | +<p>Changing it requires a restart — you cannot raise slots on a running server. If you reserve slots for admins with <code>adminslots.amxx</code>, those come out of this total: 20 slots with 2 reserved means 18 public slots and 2 held for admins.</p> | |
| 16 | + | |
| 17 | +<h2>2. Match slots to the map, first and foremost</h2> | |
| 18 | +<p>The map decides how many players is fun, more than anything else:</p> | |
| 19 | +<table> | |
| 20 | +<thead><tr><th>Content</th><th>Comfortable range</th><th>Why</th></tr></thead> | |
| 21 | +<tbody> | |
| 22 | +<tr><td>Classic de_/cs_ (dust2, inferno)</td><td>12–20</td><td>Designed around ~5v5 to 10v10; more turns chokepoints into meat grinders.</td></tr> | |
| 23 | +<tr><td>Popular 24/7 single map</td><td>18–24</td><td>Enough for constant action without total spawn chaos.</td></tr> | |
| 24 | +<tr><td>Zombie / fun / surf / deathrun</td><td>24–32</td><td>Chaos is the point; big lobbies feel alive.</td></tr> | |
| 25 | +<tr><td>Competitive / PUG</td><td>10–12</td><td>Strict 5v5 plus a spectator slot or two.</td></tr> | |
| 26 | +</tbody> | |
| 27 | +</table> | |
| 28 | +<p>Putting 32 players on a tight defusal map does not make it more popular — it makes rounds a spawn-to-death lottery, and good players leave. Big counts belong on maps and modes built for them.</p> | |
| 29 | + | |
| 30 | +<h2>3. The bandwidth budget</h2> | |
| 31 | +<p>Each occupied slot consumes upstream bandwidth bounded by <code>sv_maxrate</code>. A rough ceiling for a full server is <em>slots × sv_maxrate</em>:</p> | |
| 32 | +<pre>32 slots x 25000 bytes/s = 800,000 bytes/s | |
| 33 | + ~= 6.4 Mbit/s upstream at peak</pre> | |
| 34 | +<p>That is the worst case, but you must have the headroom or players choke. If your uplink cannot sustain the full-server rate, either lower the slot count or lower <code>sv_maxrate</code> — and lowering the rate degrades everyone's feel. Bandwidth is usually the real constraint on a home or budget host, not CPU. See the rate cvars in the <a href="/tutorials/essential-server-cvars">essential cvars list</a>.</p> | |
| 35 | + | |
| 36 | +<h2>4. The CPU / server-FPS budget</h2> | |
| 37 | +<p>More players means more entities, more traffic, and more work per tick, which pushes down your effective server FPS. A server that holds a steady high FPS at 16 players may sag at 32, and once FPS drops below your <code>sv_maxupdaterate</code> everyone gets choke on the scoreboard regardless of their own connection (see <a href="/tutorials/fix-choke-loss-scoreboard">choke and loss</a> and <a href="/tutorials/sys-ticrate-truth">the sys_ticrate truth</a>). Plugin load compounds this: a heavy zombie or stats setup at 32 slots needs real CPU. Size slots to what your box can actually push at a stable frame rate, not to the theoretical cap.</p> | |
| 38 | + | |
| 39 | +<h2>5. The population reality</h2> | |
| 40 | +<p>An empty 32-slot server looks <em>more</em> dead than an empty 16-slot one — \"3/32\" reads as a ghost town, \"3/16\" reads as a server warming up. Servers fill from a seed of players, and a smaller cap crosses the \"looks active\" threshold sooner. A practical pattern for a new server is to start smaller (16–20) so it appears busy, then raise the cap once you have a regular crowd that fills it. You can always add slots later; you cannot un-see an empty <code>4/32</code>.</p> | |
| 41 | + | |
| 42 | +<h2>6. Recommendations</h2> | |
| 43 | +<ul> | |
| 44 | +<li><strong>New public server, classic maps</strong> — 16 slots. Fills fast, plays well, cheap on resources.</li> | |
| 45 | +<li><strong>Established popular server</strong> — 20–24, once you reliably fill 16.</li> | |
| 46 | +<li><strong>Zombie / fun / minigames</strong> — 30–32, if your CPU and uplink hold FPS at full.</li> | |
| 47 | +<li><strong>Competitive</strong> — 12 (10 players + spectators), with reserved slots via <a href="/plugins/csb-reserved-slots">reserved slots</a>.</li> | |
| 48 | +</ul> | |
| 49 | + | |
| 50 | +<h2>Common errors</h2> | |
| 51 | +<ul> | |
| 52 | +<li><strong>32 slots, empty server</strong> — the big count makes a low population look dead and the wide-open lobby plays badly. Drop to 16–20 while you build a crowd.</li> | |
| 53 | +<li><strong>Choke for everyone at high population</strong> — server FPS fell below <code>sv_maxupdaterate</code> under load. Fewer slots, more CPU, or a lower update rate.</li> | |
| 54 | +<li><strong>Players rubber-band on a full server</strong> — uplink saturated: slots × <code>sv_maxrate</code> exceeds your bandwidth. Reduce one of them.</li> | |
| 55 | +<li><strong>Can't raise slots without kicking everyone</strong> — <code>maxplayers</code> is fixed at launch. Plan it, because changing it needs a restart.</li> | |
| 56 | +<li><strong>Admins can't get in on a full server</strong> — no reserved slots configured. Add <code>adminslots.amxx</code> and set the reserve count.</li> | |
| 57 | +</ul> | |
| 58 | + | |
| 59 | +<h2>Verification</h2> | |
| 60 | +<p>Confirm the running slot count and then watch performance at load. The <code>maxplayers</code> value shows in the server console and in <code>status</code>:</p> | |
| 61 | +<pre>status | |
| 62 | +// hostname, players : X (20 max) -- confirms the cap</pre> | |
| 63 | +<p>Fill the server (or use bots to simulate load) and watch server FPS with <code>stats</code> in the console. If FPS stays above your update rate and no one chokes, the count suits your hardware; if FPS sags, you are over-slotted for the box and should scale back. Set rates deliberately alongside this — see the <a href="/tutorials/essential-server-cvars">essential cvars</a> reference.</p> |
restrict-client-cvars/en.md
A
| @@ -0,0 +1,87 @@ | ||
| 1 | +--- | |
| 2 | +title: "Restricting Client Cvars (Cvar Checks and sv_consistency)" | |
| 3 | +excerpt: "Use sv_consistency and mp_consistency to force consistent models, and query_client_cvar in an AMX Mod X plugin to catch clients running cvars used to cheat." | |
| 4 | +category: "administration" | |
| 5 | +tags: "cvars, anticheat" | |
| 6 | +image: "" | |
| 7 | +read_time: "9 min read" | |
| 8 | +--- | |
| 9 | +<p>Some of the oldest CS 1.6 "cheats" are not hacks at all — they are ordinary client cvars set to values that reveal enemies through walls, remove smoke, or brighten models. The engine gives you <code>sv_consistency</code> to force consistent files, and AMX Mod X gives you <code>query_client_cvar</code> to read and reject a client's cvar values. This shows how to use both to close the easy holes.</p> | |
| 10 | + | |
| 11 | +<h2>1. Force file consistency</h2> | |
| 12 | +<p>The engine can require that clients use the server's versions of certain files (player models, sprites, sounds) rather than modified transparent or brightly-colored ones. Enable it in <a href="/tutorials/setup-server-cfg-cs16">server.cfg</a>:</p> | |
| 13 | +<pre>sv_consistency 1 | |
| 14 | +mp_consistency 1</pre> | |
| 15 | +<p><code>sv_consistency 1</code> makes the server enforce a consistency list; <code>mp_consistency 1</code> in CS specifically forces player model and skin consistency, which blocks the classic bright/see-through player skins. A client with a mismatched forced file is dropped with a consistency error rather than being allowed to play with an advantage.</p> | |
| 16 | + | |
| 17 | +<h2>2. Understand what consistency does and does not catch</h2> | |
| 18 | +<p>Consistency covers <em>files</em>. It does nothing about <em>cvars</em> — a player can still set rendering cvars that the engine honors and that give an edge. That is the gap <code>query_client_cvar</code> fills: it lets a plugin ask a connected client the value of any cvar and act on the answer. The two together — file consistency plus cvar checks — cover the common low-effort cheats. Neither replaces a real anti-cheat for signature hacks.</p> | |
| 19 | + | |
| 20 | +<h2>3. A cvar-enforcement plugin</h2> | |
| 21 | +<p>This plugin queries each player shortly after they join and kicks anyone whose value on a monitored cvar is not allowed. It uses only the core <code>amxmodx</code> API:</p> | |
| 22 | +<pre>#include <amxmodx> | |
| 23 | + | |
| 24 | +public plugin_init() | |
| 25 | +{ | |
| 26 | + register_plugin("CSB Cvar Guard", "1.0", "CSB") | |
| 27 | +} | |
| 28 | + | |
| 29 | +public client_putinserver(id) | |
| 30 | +{ | |
| 31 | + if (is_user_bot(id) || is_user_hltv(id)) | |
| 32 | + return | |
| 33 | + // give the client a moment to finish connecting | |
| 34 | + set_task(3.0, "check_cvars", id) | |
| 35 | +} | |
| 36 | + | |
| 37 | +public check_cvars(id) | |
| 38 | +{ | |
| 39 | + if (!is_user_connected(id)) | |
| 40 | + return | |
| 41 | + query_client_cvar(id, "r_drawentities", "on_cvar") | |
| 42 | + query_client_cvar(id, "gl_wireframe", "on_cvar") | |
| 43 | +} | |
| 44 | + | |
| 45 | +public on_cvar(id, const cvar[], const value[]) | |
| 46 | +{ | |
| 47 | + // r_drawentities must be 1; anything else is a rendering exploit | |
| 48 | + if (equal(cvar, "r_drawentities") && str_to_num(value) != 1) | |
| 49 | + { | |
| 50 | + server_cmd("kick #%d \"Illegal cvar: r_drawentities\"", get_user_userid(id)) | |
| 51 | + return | |
| 52 | + } | |
| 53 | + // gl_wireframe must be 0 | |
| 54 | + if (equal(cvar, "gl_wireframe") && str_to_num(value) != 0) | |
| 55 | + { | |
| 56 | + server_cmd("kick #%d \"Illegal cvar: gl_wireframe\"", get_user_userid(id)) | |
| 57 | + return | |
| 58 | + } | |
| 59 | +}</pre> | |
| 60 | +<p>Compile it, drop the <code>.amxx</code> into <code>addons/amxmodx/plugins/</code>, and add it to <a href="/tutorials/plugins-ini-load-order">plugins.ini</a>. If you would rather not maintain your own, a ready-made version ships as the <a href="/plugins/csb-cvar-guard">CSB Cvar Guard</a> plugin with a configurable list.</p> | |
| 61 | + | |
| 62 | +<h2>4. Which cvars are worth checking</h2> | |
| 63 | +<p>Values a legitimate player never needs to change, and which grant an advantage when tampered with:</p> | |
| 64 | +<ul> | |
| 65 | +<li><code>r_drawentities</code> — must be <code>1</code>; other values can alter how entities render.</li> | |
| 66 | +<li><code>gl_wireframe</code> — must be <code>0</code>; non-zero draws wireframe through geometry.</li> | |
| 67 | +<li><code>gl_zmax</code>, <code>gl_polyoffset</code> — tampering can affect depth/visibility on some renderers.</li> | |
| 68 | +</ul> | |
| 69 | +<p>Keep the list short and well-understood; over-restricting kicks legitimate players on hardware quirks. Do <strong>not</strong> guess at cvar names — query only ones you have verified exist and matter.</p> | |
| 70 | + | |
| 71 | +<h2>5. Enforce sv_cheats and rates too</h2> | |
| 72 | +<p>Two engine-side basics belong alongside cvar checks: <code>sv_cheats 0</code> (so cheat-protected cvars like <code>r_fullbright</code> cannot be set at all) and sane rate limits so nobody games the netcode. Both are in the <a href="/tutorials/essential-server-cvars">essential server cvars</a> list.</p> | |
| 73 | + | |
| 74 | +<h2>Troubleshooting</h2> | |
| 75 | +<ul> | |
| 76 | +<li><strong>Consistency kicks legitimate players</strong> — your server's forced files differ from stock in a way clients cannot obtain. Make sure the required files are on your <a href="/tutorials/fastdl-setup-guide">FastDL mirror</a> so clients can download the correct versions.</li> | |
| 77 | +<li><strong>query_client_cvar never fires</strong> — you queried too early (before the client finished connecting) or the client is a bot/HLTV. Delay with <code>set_task</code> and skip non-players, as the plugin does.</li> | |
| 78 | +<li><strong>Everyone gets kicked</strong> — your allowed value is wrong, or the cvar has a different legitimate default than you assumed. Log the values before you kick on them.</li> | |
| 79 | +<li><strong>Cheaters still get through</strong> — cvar checks only catch cvar-based tricks; binary aimbots/wallhacks need a dedicated anti-cheat. This is a floor, not a ceiling.</li> | |
| 80 | +<li><strong>Consistency does nothing</strong> — <code>sv_consistency 0</code>, or nothing is on the consistency list to enforce. Enable both cvars.</li> | |
| 81 | +</ul> | |
| 82 | + | |
| 83 | +<h2>Verification</h2> | |
| 84 | +<p>On a test client, set a monitored cvar to a bad value before connecting:</p> | |
| 85 | +<pre>gl_wireframe 1 | |
| 86 | +connect your.server.ip:27015</pre> | |
| 87 | +<p>You should be kicked within a few seconds with the <code>Illegal cvar</code> message. Set it back to <code>0</code> and confirm you connect normally. For consistency, join with a modified player model and confirm the server rejects it. When both the file check and the cvar check reject their test cases, the common low-effort cheats are closed.</p> |
spot-backdoored-amxx-plugin/en.md
A
| @@ -0,0 +1,52 @@ | ||
| 1 | +--- | |
| 2 | +title: "How to Spot a Backdoored AMXX Plugin Before You Run It" | |
| 3 | +excerpt: "The red flags in .sma source and compiled .amxx files that hand an attacker admin or RCON — hardcoded IDs, hidden commands, outbound sockets — and how to vet a plugin safely." | |
| 4 | +category: "security" | |
| 5 | +tags: "backdoor, plugins" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>A single malicious plugin can quietly grant its author full control of your server: silent admin on join, a hidden chat command that runs RCON, or a beacon that phones home with your <code>rcon_password</code>. These backdoors are common in "free plugin packs" and cracked premium plugins passed around forums. The defense is simple in principle — <strong>read the source, never run a compiled-only binary you cannot inspect</strong> — and this is the checklist for doing it.</p> | |
| 10 | + | |
| 11 | +<h2>1. Insist on source you can read</h2> | |
| 12 | +<p>The golden rule: run the <code>.sma</code>, not a mystery <code>.amxx</code>. A compiled binary handed to you with no source is the single biggest red flag, because you cannot audit it and decompilation is unreliable. Our own <a href="/plugins/csb-admin-menu">plugin directory</a> stores only source and compiles it on demand for exactly this reason — what you download is what you can read. Compile it yourself; see <a href="/tutorials/compile-sma-to-amxx">compiling .sma to .amxx</a>.</p> | |
| 13 | + | |
| 14 | +<h2>2. Grep the source for privilege grants</h2> | |
| 15 | +<p>A backdoor almost always gives someone admin flags they should not have. Search the <code>.sma</code> for the functions that set access, and check who they target:</p> | |
| 16 | +<pre>grep -iE 'set_user_flags|read_flags|ADMIN_|amx_rcon|rcon_password' plugin.sma</pre> | |
| 17 | +<p>Danger patterns:</p> | |
| 18 | +<ul> | |
| 19 | +<li><code>set_user_flags(id, read_flags("abcdef...z"))</code> called on connect for a <strong>hardcoded SteamID or name</strong> — instant silent admin for the author.</li> | |
| 20 | +<li>Any string comparison against a specific <code>STEAM_0:</code> ID or player name followed by a flag grant.</li> | |
| 21 | +<li><code>server_cmd("rcon_password ...")</code> or code that changes <code>rcon_password</code> — it is stealing or resetting your RCON.</li> | |
| 22 | +</ul> | |
| 23 | + | |
| 24 | +<h2>3. Look for hidden commands</h2> | |
| 25 | +<p>Backdoors register a secret command that only the author knows, often a harmless-looking chat trigger:</p> | |
| 26 | +<pre>grep -iE 'register_clcmd|register_concmd|register_srvcmd' plugin.sma</pre> | |
| 27 | +<p>Cross-check every registered command against what the plugin claims to do. A "round sound" plugin that registers <code>say /gimme</code> and grants admin, or a <code>register_clcmd</code> that runs <code>amx_rcon</code>-style behavior for anyone who types a magic word, is a backdoor. Legitimate commands map to the plugin's stated features; extras that do privileged things do not belong.</p> | |
| 28 | + | |
| 29 | +<h2>4. Watch for outbound network calls</h2> | |
| 30 | +<p>A plugin that talks to the internet without a reason is exfiltrating data or pulling remote commands. Check the includes and modules:</p> | |
| 31 | +<pre>grep -iE '#include *<sockets>|#include *<grip>|socket_open|socket_send' plugin.sma</pre> | |
| 32 | +<p>A GeoIP lookup uses a local database, not sockets — so an admin or "stats" plugin opening a socket to an external IP is suspicious. Legitimate uses exist (a web-based ban sync), but they should be documented and pointed at <em>your</em> endpoint, not a stranger's. Treat an undocumented outbound connection as hostile.</p> | |
| 33 | + | |
| 34 | +<h2>5. Scan a compiled .amxx if that is all you have</h2> | |
| 35 | +<p>If you are stuck with a binary, extract its strings before you even consider loading it — hardcoded backdoors often leave their fingerprints in plain text:</p> | |
| 36 | +<pre>strings plugin.amxx | grep -iE 'STEAM_|rcon|http|amx_|flags|socket'</pre> | |
| 37 | +<p>A hardcoded <code>STEAM_0:</code> ID, a URL, or <code>rcon</code> strings inside a plugin that has no business with any of them is enough to reject it. This is a smell test, not proof of safety — a clean strings dump does not clear a binary. When in doubt, do not run it.</p> | |
| 38 | + | |
| 39 | +<h2>6. Test in isolation first</h2> | |
| 40 | +<p>Vet new plugins on a throwaway test server with a unique <code>rcon_password</code> before they touch production. Load the plugin, then from the console run <code>amxx plugins</code> to confirm what loaded and watch the AMXX logs (<a href="/tutorials/debug-amxx-plugins">debug logging</a>) for unexpected command registrations or network activity. Have a second account connect and confirm nobody silently receives admin — check with the <a href="/tutorials/amxx-admin-flags-reference">flags reference</a> what each connected player actually holds.</p> | |
| 41 | + | |
| 42 | +<h2>Troubleshooting / red-flag summary</h2> | |
| 43 | +<ul> | |
| 44 | +<li><strong>Compiled-only, no source</strong> — reject by default. You cannot audit what you cannot read.</li> | |
| 45 | +<li><strong>Hardcoded SteamID or name in an access grant</strong> — backdoor. The author is giving themselves admin.</li> | |
| 46 | +<li><strong>Registered command that does not match the feature list</strong> — hidden trigger. Remove the plugin.</li> | |
| 47 | +<li><strong>Sockets/HTTP with no documented reason</strong> — exfiltration or remote control.</li> | |
| 48 | +<li><strong>Obfuscated strings, base-encoded blobs, or code that builds commands from scrambled text</strong> — deliberately hiding intent. Do not run it.</li> | |
| 49 | +</ul> | |
| 50 | + | |
| 51 | +<h2>Verification</h2> | |
| 52 | +<p>After vetting, load the plugin on the test server and prove three things: <code>amxx plugins</code> shows it <code>running</code> with no extra plugins pulled in; a non-admin test client receives no admin flags after connecting; and the server opens no unexpected outbound connections while it runs. Only then promote it to production. As a standing policy, download plugins from sources you can read and compile yourself — the same discipline that keeps <a href="/tutorials/download-cs16-server-files-safely">server files safe</a> keeps your plugin list clean.</p> | |
| 0 | 53 |









