Add 7 tutorials (7 files)
Browse Source
7 changed files
with 77 additions and 0 deletions
A
discord-server-integration/en.md
+9 -0
A
fix-different-game-version/en.md
+9 -0
A
fix-max-edicts-too-many-entities/en.md
+9 -0
A
fix-rcon-not-working-remote/en.md
+16 -0
A
fix-sound-slots-overflow/en.md
+12 -0
A
fix-zombie-plague-round-not-starting/en.md
+13 -0
A
player-retention-cs16/en.md
+9 -0
discord-server-integration/en.md
A
| @@ -0,0 +1,9 @@ | ||
| 1 | +--- | |
| 2 | +title: "Connecting Your CS 1.6 Server to Discord (Status and Alerts)" | |
| 3 | +excerpt: "How to surface live server status, join alerts and admin controls in Discord using webhooks and a bot, what CS 1.6 can and cannot push on its own, and how to do it without exposing RCON." | |
| 4 | +category: "hosting" | |
| 5 | +tags: "discord, integration" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>A Discord server is where a CS 1.6 community actually lives between sessions, so wiring your game server into it — live status, "players online now" pings, admin alerts — is one of the highest-leverage things you can set up. The important framing first: GoldSrc CS 1.6 has no native Discord support. Everything here is done by an external process that either queries your server (A2S) or reads its logs, then posts to Discord through a webhook or a bot. Here is how the pieces fit.</p><h2>1. Decide what you want in Discord</h2><p>Three distinct integrations, in rising order of complexity:</p><ul><li><strong>Live status</strong> — a channel or bot presence showing current map and player count, updated every minute.</li><li><strong>Event alerts</strong> — a message when the server fills past a threshold, empties, or crashes.</li><li><strong>Two-way control</strong> — running RCON commands from Discord (status, changelevel, kick).</li></ul><p>Pick the minimum you need; two-way control is powerful but carries real risk if the bot is compromised.</p><h2>2. Create a Discord webhook for one-way alerts</h2><p>For status and alerts you do not need a full bot — a channel webhook is enough. In Discord: <strong>Channel Settings → Integrations → Webhooks → New Webhook</strong>, name it, and copy the webhook URL. Any process that can make an HTTPS POST can now post to that channel. Treat the webhook URL like a password — anyone who has it can post as your bot — so keep it out of public configs and out of your MOTD.</p><h2>3. Push live status by querying the server</h2><p>The clean, safe way to show status is to query the server from outside using the same A2S_INFO the game browser uses — it needs no access to the box, only your public <code>IP:port</code>. A small scheduled script queries the server, formats map and player count, and POSTs to the webhook. Because it only reads the public query port, it cannot be turned against your server. This is exactly how uptime tools work; if you already run one, see <a href="/tutorials/monitor-server-uptime-alerts">monitoring uptime with alerts</a> and point its notifications at the Discord webhook.</p><h2>4. Turn join and connect events into pings</h2><p>To announce players joining, you have two options. The query-based script above can detect the count rising and post "3 players online — come play". For richer, per-player events (who connected, from where), read the server log — CS 1.6 writes connect lines to its log files, and a log-tailing script can post them. An in-game connect announcer such as <a href="/plugins/csb-connect-announce-geoip">CSB Connect Announce (GeoIP)</a> shows joins to players on the server; pairing it with a log-tail-to-Discord bridge gets the same information into your Discord for the people who are not in-game yet.</p><h2>5. Two-way RCON — only through a bot, never a raw password</h2><p>Running commands from Discord means a bot that holds your RCON password and executes commands on the server. This is genuinely useful for admins but must be locked down: restrict the command to specific Discord roles, never post the RCON password in any channel, and rotate it if the bot host is ever exposed. The full pattern — bot, role gate, command whitelist — is covered in <a href="/tutorials/discord-rcon-bot">the Discord RCON bot guide</a>. First harden RCON itself per <a href="/tutorials/rcon-setup-secure">secure RCON setup</a>; a Discord bridge is only as safe as the RCON behind it.</p><h2>Common errors</h2><ul><li><strong>Webhook posts nothing</strong> — the URL is wrong or the webhook was deleted. Re-create it and test with a single manual POST.</li><li><strong>Status always shows offline</strong> — your query script cannot reach the server. Confirm the public port is open and the server is in the browser; A2S uses the same UDP port as the game.</li><li><strong>Duplicate or spammy pings</strong> — the script fires on every poll instead of on state change. Announce only when the count crosses a threshold, not every cycle.</li><li><strong>Bot leaked the RCON password</strong> — someone with channel access read a logged command. Never echo RCON back to Discord; rotate the password immediately.</li><li><strong>Wrong player count</strong> — the server pads with fake players, which A2S reports literally. See <a href="/tutorials/fake-players-bot-padding">fake players and bot padding</a>.</li></ul><h2>Verification</h2><p>Post one test message through the webhook and confirm it appears in the channel. Start your status script and watch it update the map and count when you change the map in-game — the Discord message should follow within one poll interval. For the RCON bot, run a harmless command such as <code>status</code> from an authorized role and confirm the response, then confirm an unauthorized user is refused. When status tracks reality and only permitted roles can issue commands, the integration is sound.</p> |
fix-different-game-version/en.md
A
| @@ -0,0 +1,9 @@ | ||
| 1 | +--- | |
| 2 | +title: "Fix: 'You are running a different version of the game'" | |
| 3 | +excerpt: "What the protocol-mismatch rejection actually means, why the 25th Anniversary update caused a wave of it, matching client and server builds, and the steam_legacy rollback for both sides." | |
| 4 | +category: "errors" | |
| 5 | +tags: "version, protocol" | |
| 6 | +image: "" | |
| 7 | +read_time: "7 min read" | |
| 8 | +--- | |
| 9 | +<p>A player tries to connect and is bounced immediately with:</p><blockquote>You are running a different version of the game</blockquote><p>or the closely related engine message on older builds. This is a <strong>protocol/build mismatch</strong>: the client and the server were built against incompatible engine versions and refuse to talk. It is not a bad password or a ban — it is the handshake deciding the two ends are not the same game. Here is how to line them up.</p><h2>1. Understand what mismatched</h2><p>CS 1.6 connections negotiate a protocol version. When Valve ships an engine update, clients that auto-updated speak the new protocol while a server still on the old binary speaks the old one, and vice-versa. The 2023 <strong>25th Anniversary update</strong> was the big one: it changed the engine and broke connections between updated and non-updated ends across the whole ecosystem overnight. Most modern occurrences of this error trace back to one side updating and the other not.</p><h2>2. If you run the server: match your build to current clients</h2><p>If your players are on regular, auto-updating Steam clients, your server must run a build that speaks the current protocol. On <strong>HLDS</strong>, update through SteamCMD:</p><pre>./steamcmd.sh +force_install_dir /home/cs/hlds +login anonymous +app_update 90 validate +quit</pre><p>App <code>90</code> is the dedicated server. <code>validate</code> repairs a half-updated install. If you run <strong>ReHLDS</strong> instead of stock HLDS, update the ReHLDS binary from the <code>rehlds</code> project to a release that targets the current engine protocol, keeping your ReHLDS <code>swds</code>/<code>engine</code> library in step with the base HLDS files it patches. A ReHLDS built against an older protocol than your clients throws exactly this error. After updating, always <code>validate</code> once so a half-downloaded engine file does not leave you with a binary that speaks neither protocol cleanly.</p><p>One nuance worth knowing: the master-server listing and the direct-connect handshake are separate. A player can sometimes see your server in the browser but still be rejected on connect with this message, because the browser query succeeded while the protocol negotiation failed. That combination — visible but unjoinable — almost always means a build mismatch rather than a firewall problem.</p><h2>3. If you host non-Steam players: pin everyone to one protocol</h2><p>Non-Steam communities often standardise on a specific client build and a matching server so nobody mismatches. If your audience runs a particular older client, your server must speak that protocol. This is where <a href="/tutorials/fix-dproto-clients-rejected">dproto</a> or Reunion matters: those emulators must be configured for a protocol the clients actually use. A server forced to protocol 48 while clients speak 47 (or the reverse) rejects them with this message.</p><h2>4. Roll a client back to the legacy build</h2><p>If a single player gets the error against a server everyone else joins, that player's client updated past the server. They can roll back to the pre-Anniversary build in Steam: right-click Counter-Strike → Properties → Betas, and select the <code>steam_legacy</code> branch from the dropdown. Steam downloads the older engine, which speaks the older protocol and matches a legacy server.</p><h2>5. Roll the server back instead</h2><p>The mirror image: if updating clients broke <em>your</em> server and you cannot immediately move to a current-protocol build, put the server on the legacy line too. For a SteamCMD HLDS install you install the matching legacy app build; for a manual install you deploy the pre-update binaries. The whole point is that <strong>both ends must be on the same side of the Anniversary update</strong> — either both current or both legacy. Mixing them is what produces the error.</p><h2>Common errors</h2><ul><li><strong>Everyone gets it after a Valve update</strong> — the server is behind. Run <code>app_update 90 validate</code> (HLDS) or update your ReHLDS binary.</li><li><strong>Only one player gets it</strong> — that client updated past the server. Roll them to <code>steam_legacy</code>, or bring the server current.</li><li><strong>Non-Steam clients rejected with a version message</strong> — the dproto/Reunion protocol setting does not match the clients. Align the emulator's protocol.</li><li><strong>Error returned after a server reinstall</strong> — you deployed a ReHLDS build newer or older than the HLDS files it patches. Keep them in step.</li><li><strong>Works on LAN, fails from the internet</strong> — different, this is not a version problem; check <code>sv_lan</code> and your port forward instead.</li></ul><h2>Verification</h2><p>From the server console, confirm the running engine build:</p><pre>version</pre><p>Note it, then have an affected player check their client build under Help → About or the console <code>version</code>. Both ends should be on the same side of the Anniversary update. Have the player reconnect; a clean join with no rejection confirms the protocols now match. If you standardised on the legacy branch, make sure new players know to select <code>steam_legacy</code> before connecting, and advertise it in your <a href="/tutorials/motd-txt-html-guide">MOTD</a>.</p> |
fix-max-edicts-too-many-entities/en.md
A
| @@ -0,0 +1,9 @@ | ||
| 1 | +--- | |
| 2 | +title: "Fix: 'Too many entities' / MAX_EDICTS Reached" | |
| 3 | +excerpt: "What an edict is, why GoldSrc runs out of them, reading the 'ED_Alloc: no free edicts' crash, finding the plugin that leaks entities, and raising the limit on ReHLDS." | |
| 4 | +category: "errors" | |
| 5 | +tags: "edicts, entities" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>The server crashes or drops everyone with a message about edicts or too many entities, usually mid-round on a busy map. An <strong>edict</strong> is an entity slot — every player, weapon, grenade, door, decal spawner, and scripted effect consumes one. Classic GoldSrc has a hard ceiling on how many can exist at once, and when a map plus your plugins push past it the engine cannot allocate another and aborts. The fix is either to stop something leaking edicts or to raise the ceiling on an engine that supports it.</p><h2>1. Read the actual error</h2><p>The engine reports this a few ways; quote the one you have when you search:</p><pre>ED_Alloc: no free edicts</pre><p>means the allocator is completely out of slots. You may also see a precache-time variant:</p><pre>Host_Error: PF_precache_*: overflow</pre><p>which is a different limit (too many distinct models/sounds precached) but is frequently confused with the edict ceiling. The edict crash happens during play as entities spawn; the precache crash happens at map load. Knowing which one you have decides the fix.</p><h2>2. Understand the ceiling</h2><p>Stock HLDS has a fixed maximum number of edicts compiled into the engine, and it is not large by modern plugin standards. A vanilla map uses a few hundred. Problems start when a plugin spawns entities faster than it removes them — temporary sprites, laser beams, dropped weapons, ammo boxes, zombie ragdolls — and the count creeps up round after round until it hits the wall. On stock HLDS you cannot raise this number; you must reduce consumption. On <a href="/tutorials/install-rehlds-on-linux">ReHLDS</a> you have a lever (step 5).</p><h2>3. Find the plugin that leaks</h2><p>Watch the entity count climb. Many admin/stats plugins expose it, or you can reason it out: if the crash always happens after N rounds regardless of map, something accumulates entities each round and never frees them. Prime suspects are effect-heavy plugins — grenade trails, weapon skins that spawn view entities, deagle/knife effects, currency drops, zombie mod ragdolls, and anything that calls a create-entity native inside a per-frame or per-kill event without a matching remove. Disable candidates one at a time in <a href="/tutorials/plugins-ini-load-order">plugins.ini</a>, change map, and see whether the slow leak stops.</p><h2>4. Reduce entity pressure</h2><p>Independent of any single plugin, cut the baseline:</p><ul><li>Lower decal churn: a high player count spraying and shooting piles up decal edicts. A stricter <code>decalfrequency</code> helps.</li><li>Trim effect plugins on high-slot servers — a 32-slot server has far less edict headroom per player than a 12-slot one.</li><li>Prefer plugins that use temporary/TE messages (which do not consume a persistent edict) over ones that spawn real entities for cosmetic effects.</li><li>Cap dropped-weapon lifetime so the map cleans up guns instead of leaving dozens on the floor.</li></ul><h2>5. Raise the limit on ReHLDS</h2><p>If you run ReHLDS, the maximum edicts is configurable rather than hardcoded. ReHLDS exposes it through its own setting so you can give the engine more slots than the legacy ceiling. Raise it in measured steps — do not jump to an absurd value, because every edict costs memory and a high cap can mask a genuine leak that will eventually bite anyway. Combine a modest raise with fixing the leaking plugin from step 3; the raise buys headroom, the fix removes the cause.</p><h2>Troubleshooting</h2><ul><li><strong><code>ED_Alloc: no free edicts</code> after a fixed number of rounds</strong> — a plugin leaks entities per round. Bisect plugins to find it.</li><li><strong>Crash at map load, not during play</strong> — that is a precache overflow (<code>PF_precache_*: overflow</code>), not the edict limit. Reduce custom models/sounds the map or plugins precache.</li><li><strong>Only high-population maps crash</strong> — you are near the ceiling and player count tips it over. Reduce effect plugins or, on ReHLDS, raise the cap.</li><li><strong>Raised the cap on stock HLDS and nothing changed</strong> — the setting only exists on ReHLDS. Stock engines cannot go past the built-in number; switch engines or cut usage.</li><li><strong>Count never drops between rounds</strong> — the round-restart cleanup is not removing plugin entities; that is the leak, confirmed.</li></ul><h2>Verification</h2><p>After the change, play through more rounds than it previously took to crash, on your busiest map at full population, while watching the entity count. If the count now plateaus round to round instead of climbing without bound, the leak is fixed. If you raised the ReHLDS cap, confirm the new headroom by loading your heaviest map at max slots and triggering the effects that used to crash it — a full round of grenades and kills — and confirm it holds. A stable, non-growing edict count across a full map rotation is the real success signal; a higher cap that still climbs forever just delays the same crash.</p> |
fix-rcon-not-working-remote/en.md
A
| @@ -0,0 +1,16 @@ | ||
| 1 | +--- | |
| 2 | +title: "Fix: RCON Works Locally but Not Remotely" | |
| 3 | +excerpt: "Why rcon succeeds from the server box but 'Bad rcon_password' or timeouts hit from outside, how the RCON challenge works, the sv_rcon and firewall settings that block it, and how to test it safely." | |
| 4 | +category: "errors" | |
| 5 | +tags: "rcon, networking" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>RCON commands run fine when you are on the server machine, but from your desktop you get <code>Bad rcon_password</code>, a silent timeout, or <code>Lost connection to server</code>. Remote RCON in GoldSrc rides the same UDP port as game traffic and uses a challenge handshake, so the failure is almost always the password, the firewall on that UDP port, or a mismatch between the address you set and the address you connect to. Here is how to isolate which.</p><h2>1. Understand how RCON authenticates</h2><p>RCON is not a persistent login. Each command does a two-step exchange over UDP 27015: the client asks for a challenge, the server returns a number, and the client re-sends the command with the password and that challenge. Anything that blocks UDP in either direction, or a password mismatch, aborts the exchange. Because it is UDP, a firewall that only opened the port one-way still breaks the reply, which is why a command can appear to hang forever rather than fail cleanly.</p><h2>2. Set the password server-side correctly</h2><p>The server must have a non-empty RCON password loaded. Set it in <a href="/tutorials/setup-server-cfg-cs16">server.cfg</a>, not on the command line where it can be seen:</p><pre>rcon_password "a-long-random-string"</pre><p>Confirm it actually loaded by running <code>rcon_password</code> with no value in the server console — an empty value means <code>server.cfg</code> did not execute or the line is commented. An empty <code>rcon_password</code> disables RCON entirely, and every remote attempt then returns <code>Bad rcon_password</code> no matter what you send.</p><h2>3. Set the password on the client the right way</h2><p>From your client console you must set the password and target the server before sending commands:</p><pre>setinfo "password" "" | |
| 10 | +rcon_password "a-long-random-string" | |
| 11 | +rcon status</pre><p>If you are not currently connected to the server, RCON needs to know where to send the command via <code>rcon_address</code> and <code>rcon_port</code>:</p><pre>rcon_address 203.0.113.10 | |
| 12 | +rcon_port 27015 | |
| 13 | +rcon status</pre><p>A frequent mistake is setting <code>rcon_password</code> but leaving <code>rcon_address</code> pointed at a stale server, so the command goes to the wrong box and returns <code>Bad rcon_password</code> from that unrelated server.</p><h2>4. Open the UDP port both ways</h2><p>RCON uses the game's UDP port. If a host firewall or cloud security group only allows inbound game traffic but drops the RCON challenge reply, or blocks the port entirely for your source IP, you get a timeout with no error text. On a Linux host confirm the port is open for UDP:</p><pre>iptables -L -n | grep 27015 | |
| 14 | +ss -lun | grep 27015</pre><p>The server must be listening on UDP 27015 (<code>ss -lun</code> shows it), and the firewall must allow UDP 27015 from your address in <strong>both</strong> directions. On a cloud provider, add UDP 27015 to the security group; a rule that only covers TCP does nothing for CS 1.6, which is UDP-only.</p><h2>5. Check sv_rcon_banpenalty and lockout</h2><p>GoldSrc locks out an IP after repeated bad RCON attempts. If you fat-fingered the password several times while testing, the server may be refusing you specifically. The relevant cvars:</p><pre>sv_rcon_minfailures 5 | |
| 15 | +sv_rcon_maxfailures 10 | |
| 16 | +sv_rcon_banpenalty 0</pre><p>If <code>sv_rcon_banpenalty</code> is non-zero, a locked-out client stays banned from RCON for that many minutes even with the correct password. Restart the map or wait out the penalty, then retry with the right password once. Setting a modest penalty is good practice against brute force, but it is also why your own testing can lock you out mid-session.</p><h2>Troubleshooting</h2><ul><li><strong><code>Bad rcon_password</code> from remote, fine locally</strong> — the client password does not match, or <code>rcon_address</code> points at a different server. Re-set both and retry.</li><li><strong>Command hangs / times out</strong> — UDP 27015 is blocked one-way by the firewall or security group. Open it inbound and outbound for your IP.</li><li><strong><code>Lost connection to server</code></strong> — you are querying an address where nothing is listening, or the port is wrong. Verify with <code>ss -lun</code>.</li><li><strong>Worked, then suddenly rejected</strong> — RCON ban penalty from failed attempts. Check <code>sv_rcon_banpenalty</code> and wait it out.</li><li><strong>Empty <code>rcon_password</code> on the server</strong> — RCON is disabled entirely. Set it in server.cfg and confirm it loaded.</li><li><strong>Works from LAN, not WAN</strong> — you are behind NAT and the port is not forwarded to the server's internal IP for UDP.</li></ul><h2>Verification</h2><p>From the remote client, after setting the password and address, run <code>rcon status</code>. A correct setup returns the player list and server hostname. Then run a harmless command such as <code>rcon stats</code> and confirm it executes. If <code>status</code> works remotely, RCON is fully functional and any later failure is a re-typed password or a changed address. For running the server behind a control plane where the port is remapped, confirm the RCON port matches the external allocation as described in the <a href="/tutorials/fix-pterodactyl-cs16-wont-start">panel startup guide</a>. Never share the RCON password in a bind or config you distribute.</p> |
fix-sound-slots-overflow/en.md
A
| @@ -0,0 +1,12 @@ | ||
| 1 | +--- | |
| 2 | +title: "Fix: 'S_FindName: out of sound slots' / Sound Precache Overflow" | |
| 3 | +excerpt: "What the sound-precache limit is in GoldSrc, why plugins that precache too many sounds crash the server, and how to find and trim the offender so the map loads." | |
| 4 | +category: "errors" | |
| 5 | +tags: "precache, sounds" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>Your server crashes on map load or when a plugin fires, and the console shows <code>S_FindName: out of sound slots</code> or <code>PF_precache_sound_I: '<file>' overflow</code>. Both are the same underlying problem: GoldSrc reserves a fixed number of slots for precached sounds, and something — usually a stack of plugins each precaching their own sound pack — has run past that ceiling. The engine cannot register more, so it aborts. This is how to find what is eating the slots and cut it back.</p><h2>1. Understand the hard limit</h2><p>GoldSrc precaches every sound a map might play at load time into a fixed table (historically 512 slots). Maps, the base game, and every plugin that calls <code>precache_sound</code> all draw from the <em>same</em> pool. You do not get 512 per plugin — you get 512 total. A single ambient-sounds plugin, a hitsound plugin, a round-sound plugin and a quake-sounds plugin stacked together can each add dozens of files and blow the budget on a content-heavy map. The error is not a corrupt file; it is arithmetic.</p><h2>2. Read the error precisely</h2><p>Two forms show up, and they mean slightly different things:</p><pre>S_FindName: out of sound slots | |
| 10 | +PF_precache_sound_I: 'sound/foo/bar.wav' overflow</pre><p>The second form names the exact file that tipped it over — the last one that tried to register when the table was already full. That file is not necessarily the guilty party; it is simply the straw. The real cause is the total, so do not just delete that one sound and assume you are done.</p><h2>3. Count what each plugin precaches</h2><p>Precaching happens in <code>plugin_precache()</code> and on map start. Disable plugins one at a time to see which ones are heavy. Comment a line in <code>addons/amxmodx/configs/plugins.ini</code> (see <a href="/tutorials/plugins-ini-load-order">plugins.ini load order</a>), change map, and watch whether the overflow clears:</p><pre>; ambience_sounds.amxx | |
| 11 | +; quake_sounds.amxx</pre><p>Sound-pack plugins are the usual suspects: quake/HLDM announcer sounds, hitsound packs, ambient map sounds, custom bomb/round sounds. Each can register 20–80 files. Start with those. The moment the map loads without the error after disabling one, you have found a major contributor.</p><h2>4. Trim the sound sets, do not just disable</h2><p>You rarely need to remove a whole plugin — you need to shrink its sound list. Most sound plugins keep their file list in a config or a directory:</p><pre>addons/amxmodx/configs/ (plugin .cfg or .ini with a sound list) | |
| 12 | +cstrike/sound/ (the .wav files themselves)</pre><p>Edit the plugin's sound list down to the ones you actually want. A quake-sounds plugin with 40 announcer variations can lose the redundant ones and free 30 slots instantly. If two plugins precache the <em>same</em> sound, that is double-spend — consolidate onto one plugin.</p><h2>5. Check for a runtime precache mistake</h2><p>Precaching must happen at <code>plugin_precache</code>/map start, never mid-round. A plugin that calls <code>precache_sound</code> in a runtime event (on a kill, on a chat command) will keep adding slots as the map runs and eventually overflow even if the load was fine. If the crash happens after minutes of play rather than at load, look for a plugin precaching on the fly — that is a bug in the plugin, and a maintained one from the <a href="/plugins/csb-admin-menu">plugin directory</a> will not do it.</p><h2>Troubleshooting</h2><ul><li><strong>Overflow only on certain maps</strong> — those maps ship many custom sounds of their own, leaving less room for plugins. Trim plugin sounds so the total fits the heaviest map.</li><li><strong>Names a specific file in the overflow</strong> — that file is the straw, not the cause. Reduce the <em>total</em> count, not just that one.</li><li><strong>Clears when you disable one plugin</strong> — that plugin is heavy but you can likely keep it by shrinking its sound list instead of removing it.</li><li><strong>Crash appears minutes into a map, not at load</strong> — a plugin is precaching at runtime. That is a plugin bug; replace it.</li><li><strong>Also seeing model/generic overflow</strong> — the same fixed-table problem hits models and generic files too. The approach is identical: count and trim.</li></ul><h2>Verification</h2><p>Load your heaviest custom map with the full plugin set and confirm the console shows no <code>out of sound slots</code> or <code>overflow</code> line during precache. Play a full round and trigger every sound-producing plugin — hitsounds, round end, ambience — and confirm the server stays up. If it survives the busiest map with all sound plugins active, you are inside the budget. Keep a note of roughly how many sounds each plugin adds so the next plugin you install does not silently push you back over the edge.</p> |
fix-zombie-plague-round-not-starting/en.md
A
| @@ -0,0 +1,13 @@ | ||
| 1 | +--- | |
| 2 | +title: "Fix: Zombie Plague Round Doesn't Start" | |
| 3 | +excerpt: "Why a Zombie Plague server sits in an endless standard round with no infection, the plugin load order and cvars that gate the mode, and how to read the AMXX log to find the real cause." | |
| 4 | +category: "errors" | |
| 5 | +tags: "zombie-plague, mods" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>You installed Zombie Plague, the map loads, players spawn — and the round just plays out like normal Counter-Strike. No one turns into the first zombie, the mode never triggers, and the HUD that should announce the infection never appears. The mod is loaded but the <em>round mode</em> is not starting. This is almost always one of four things: a plugin that failed to load, a wrong load order, a cvar or delay that gates the first infection, or too few players. Work through them in that order.</p><h2>1. Confirm every Zombie Plague plugin actually loaded</h2><p>Zombie Plague is not one file — it is a core plugin plus a set of sub-plugins (classes, items, extra modes). If the core failed to load, nothing triggers. Check the plugin list from the server console:</p><pre>amxx plugins</pre><p>Find <code>zombie_plague40.amxx</code> (or your version's core file) and confirm it reads <code>running</code>, not <code>bad load</code> or <code>debug</code>. A <code>bad load</code> means the core never initialised, so it never schedules the first infection. If you see it, open the AMX Mod X log to find out why — that is step 4. For a clean install from scratch, follow the <a href="/tutorials/install-zombie-plague-mod">Zombie Plague install guide</a>; our own maintained core is <a href="/plugins/csb-zombie-core">CSB Zombie Core</a>.</p><h2>2. Fix the load order</h2><p>The sub-plugins depend on natives the core registers, so the core must load <strong>before</strong> everything that extends it. In <code>addons/amxmodx/configs/plugins.ini</code> the core line comes first, then the add-ons:</p><pre>zombie_plague40.amxx | |
| 10 | +zp_class_nemesis.amxx | |
| 11 | +zp_class_assassin.amxx | |
| 12 | +zp_extra_infbomb.amxx</pre><p>If a sub-plugin is listed above the core it will fail with an undefined-native error and can drag the mode down with it. The rules for this are in <a href="/tutorials/plugins-ini-load-order">plugins.ini load order</a>. Change the map after editing, because <code>plugins.ini</code> is only re-read on map change.</p><h2>3. Check the cvars that gate the first infection</h2><p>Zombie Plague waits before infecting, and it needs a minimum number of players. Two settings decide whether the round ever converts. They live in the mod's config, usually <code>addons/amxmodx/configs/zombie_plague/zp_config.cfg</code> or <code>zombieplague.cfg</code>:</p><pre>zp_delay 10 // seconds after round start before first zombie is chosen | |
| 13 | +zp_required_players 2 // minimum humans before the mode activates</pre><p>The second one is the usual culprit on a quiet server: with <code>zp_required_players 2</code> and only one person connected, the mode correctly refuses to start and you get a plain round. Lower it to test alone, but restore a sane value afterward — a single-player infection round is pointless in practice. If <code>zp_delay</code> was set absurdly high, the infection is coming, just much later than you expected. Read the values back with the cvar name and no argument to see what is really set.</p><h2>4. Read the AMXX log for the real error</h2><p>If the core shows <code>bad load</code> or the mode still will not fire, the reason is written down. Open the current error log:</p><pre>addons/amxmodx/logs/error_<date>.log</pre><p>Two messages are common here. A missing dependency:</p><blockquote>Plugin "zombie_plague40.amxx" failed to load: Module/Library "cstrike" required for plugin. Check modules.ini.</blockquote><p>— means a required module (often <code>cstrike</code>, <code>fun</code>, <code>fakemeta</code> or <code>hamsandwich</code>) is not enabled in <code>modules.ini</code>; enable it and restart. Or a native error:</p><blockquote>Run time error 10: native error (native "...")</blockquote><p>— usually a sub-plugin loading before the core, i.e. the load-order problem from step 2. The full method for reading these lines is in <a href="/tutorials/read-amxx-error-log">reading the AMXX error log</a> and <a href="/tutorials/debug-amxx-plugins">debugging AMXX plugins</a>.</p><h2>Common errors</h2><ul><li><strong>Round plays as normal CS, no infection</strong> — too few players for <code>zp_required_players</code>, or the core is <code>bad load</code>. Check both.</li><li><strong>'failed to load: Module ... required'</strong> — a needed module is off in <code>modules.ini</code>. Enable it and restart.</li><li><strong>Sub-plugin throws a native error</strong> — it loads before the core. Move the core line to the top of <code>plugins.ini</code>.</li><li><strong>Infection eventually happens but very late</strong> — <code>zp_delay</code> is set high. Lower it to a few seconds.</li><li><strong>Everything loads but weapons/models are wrong</strong> — that is a resources issue, not the round trigger; check precache and FastDL, not the mode cvars.</li></ul><h2>Verification</h2><p>Set <code>zp_required_players 1</code> temporarily, change the map, and join. Within <code>zp_delay</code> seconds the server should pick a first zombie and the infection HUD should appear. Confirm the core is healthy with <code>amxx plugins</code> (it reads <code>running</code>) and that the current <code>error_*.log</code> gained no new lines during the round. Once the mode fires reliably, put <code>zp_required_players</code> back to a realistic value for your player count so rounds only convert when there are enough humans to make them fun.</p> |
player-retention-cs16/en.md
A
| @@ -0,0 +1,9 @@ | ||
| 1 | +--- | |
| 2 | +title: "Player Retention: Why People Leave Your CS 1.6 Server" | |
| 3 | +excerpt: "The concrete, fixable reasons players quit a CS 1.6 server on the first minute and never return: lag, empty prime time, unbalanced teams, cheaters, and a dead map rotation." | |
| 4 | +category: "hosting" | |
| 5 | +tags: "retention, community" | |
| 6 | +image: "" | |
| 7 | +read_time: "8 min read" | |
| 8 | +--- | |
| 9 | +<p>Getting a player to connect is the easy half; keeping them past the first two rounds is the whole game. Most CS 1.6 servers do not have a marketing problem, they have a retention problem — players join, hit one friction point, and disconnect forever. The good news is that almost every reason is technical and fixable. This is a diagnostic pass through the things that make people leave, roughly in the order a new connector encounters them.</p><h2>1. The first-minute killers: lag and downloads</h2><p>A player who chokes on connect never sees your gameplay. Two things dominate the first sixty seconds. First, <strong>ping and choke</strong>: if the server runs poor FPS or the client's rates are wrong, they see warping and quit. Make sure your server holds stable FPS (see <a href="/tutorials/stable-1000-fps-linux-server">stable server FPS</a>) and that rate cvars are sane per <a href="/tutorials/sv-maxrate-maxupdaterate-values">maxrate and maxupdaterate values</a>. Second, <strong>slow downloads</strong>: if joining triggers a multi-megabyte in-game file transfer at a few KB/s, they stare at a loading bar and leave. A working <a href="/tutorials/fastdl-setup-guide">FastDL</a> mirror turns a 60-second wait into two seconds.</p><h2>2. An empty server stays empty</h2><p>Players join servers that already have players. An empty server at your prime time is the number-one retention leak because nobody wants to be the only one there. Concentrate your population — if you run several servers, do not split a small community across all of them; fill one first. Use the <a href="/tutorials/track-player-counts-peak-hours">peak-hours data</a> to know when your regulars log on and be present yourself at that hour. A few real players at 8pm seed the rest of the night, and once a browser sees a non-zero count the server sells itself. This is why filling a single server is worth more than spreading thin across three empty ones.</p><h2>3. Unbalanced teams and stomps</h2><p>Nothing empties a server faster than a 12-versus-4 blowout. New players land on the losing side, get farmed, and leave. Run automatic <a href="/plugins/csb-team-balance">team balancing</a> so a lopsided scramble self-corrects, and consider a <a href="/plugins/csb-spawn-protection">spawn protection</a> window so a fresh connector is not headshot in the spawn before they can move. Retention is highest when a mediocre player can still get a couple of kills.</p><h2>4. Cheaters drive out everyone honest</h2><p>One blatant aimbot in prime time can cost you a night's regulars. You cannot catch everything, but you can raise the floor: run <a href="/tutorials/install-rechecker">ReChecker</a> to enforce client file integrity, a detection plugin such as <a href="/plugins/csb-aimbot-detect">aimbot detection</a>, and be reachable so players can report. A visibly moderated server keeps honest players; an unmoderated one becomes a cheat lobby. See <a href="/tutorials/prevent-steamid-spoofing">preventing SteamID spoofing</a> for the identity side.</p><h2>5. A stale map rotation and no reason to stay</h2><p>The same three maps forever bores your regulars into leaving for variety. Give players agency with <a href="/tutorials/rtv-nextmap-setup">Rock The Vote and nextmap</a> so they steer the rotation, keep a <a href="/tutorials/mapcycle-txt-setup">mapcycle</a> broad enough to stay fresh but not so broad it is full of maps nobody likes, and add a light progression hook — a <a href="/tutorials/setup-stats-system">rank system</a> gives players a number to climb, which is a concrete reason to reconnect tomorrow.</p><h2>Common mistakes</h2><ul><li><strong>High player churn but good ping</strong> — check downloads and team balance before blaming the network; a stomp empties a low-latency server just as fast.</li><li><strong>Server fills then empties every night at the same time</strong> — a recurring stomp, a lag spike from a cron job, or a map everyone hates in the rotation. Correlate the drop-off time with your logs.</li><li><strong>Regulars quietly stop coming</strong> — usually cheaters or boredom. Ask them; a small community will tell you exactly what broke.</li><li><strong>New players never stay</strong> — the first minute is too hostile: slow download, instant spawn death, or a wall of adverts. Smooth the on-ramp.</li><li><strong>Population split across servers</strong> — consolidate. Two half-full servers retain worse than one full one.</li></ul><h2>Verification</h2><p>Connect as a brand-new player would — from a clean client with no custom content — and time how long from connect to first spawn. Under ten seconds is healthy; a minute means fix downloads. Then watch a full prime-time session and note the exact moment players drop: a score, a map, a specific event. That timestamp, cross-referenced with your <a href="/tutorials/parse-cs16-server-logs">server logs</a>, points straight at the leak. Retention is not one fix, it is closing these holes one at a time until players stop having a reason to leave.</p> | |
| 0 | 10 |









