No description
Find a file
Astra 63e07d12c8 0.2.1: don't read the player list in OnAllPluginsLoaded at server start
It isn't readable before the server has set up (Global Variables not
initialized yet). Online players' blocks are only read there on a hot
reload; at start everyone's load as they join.
2026-10-07 09:36:08 +01:00
lib Whisper 0.1.0: private messages between players 2026-10-05 13:13:58 +01:00
Migrations 0.2.0: keep all chat, @ staff chat and SimpleAdmin's say commands too 2026-10-05 14:57:19 +01:00
.gitignore Whisper 0.1.0: private messages between players 2026-10-05 13:13:58 +01:00
Config.cs Whisper 0.1.0: private messages between players 2026-10-05 13:13:58 +01:00
Database.cs 0.2.0: keep all chat, @ staff chat and SimpleAdmin's say commands too 2026-10-05 14:57:19 +01:00
Ops.cs 0.2.0: keep all chat, @ staff chat and SimpleAdmin's say commands too 2026-10-05 14:57:19 +01:00
README.md README: typo 2026-10-05 14:57:24 +01:00
release.sh Whisper 0.1.0: private messages between players 2026-10-05 13:13:58 +01:00
Tags.cs Whisper 0.1.0: private messages between players 2026-10-05 13:13:58 +01:00
Whisper.cs 0.2.1: don't read the player list in OnAllPluginsLoaded at server start 2026-10-07 09:36:08 +01:00
Whisper.csproj Whisper 0.1.0: private messages between players 2026-10-05 13:13:58 +01:00
Writer.cs Whisper 0.1.0: private messages between players 2026-10-05 13:13:58 +01:00

Whisper

Private messages between players, for CounterStrikeSharp 1.0.376 (net10.0), alongside CS2-SimpleAdmin and CS2-Tags.

Commands

Chat Console What
/pm <target> <message>, /w css_pm, css_w Send a private message
/r <message> css_r Reply to whoever last messaged you
/block <#userid|steamid64> css_block Stop a player messaging you. A SteamID64 works while they're offline
/blocklist css_blocklist Your blocks, numbered from 1
/unblock <number> css_unblock Remove that block
css_whisper_history <on|off> @css/root and the server console: see History

! works the same as /. The plugin takes these commands out of chat itself, so !pm never shows the message to everyone the way a ! command normally would.

Targets are one player:

  • part of a name (an exact match wins when several names contain it), or "a name with spaces";
  • #userid, as css_players and status show it, a SteamID64 (with or without #) or a STEAM_ ID;
  • @me, @aim (who you're looking at), @randomt, @randomct, or @random (anyone on any team, alive, dead or spectating).

Group targets (@all, @t, @ct, @spec, @alive, @dead, @bots, @human, @!me) are refused. Bots and SourceTV can't be messaged. Admins hidden with SimpleAdmin's css_hide can't be found, so a message doesn't give them away; staff (StaffPermission) still can. Random picks never land on you or a hidden admin.

Messages

>[[M] Kalus → me] rotate b       what Bravo sees
>[[M] Kalus → Bravo] rotate b    what Kalus sees

The sender's rank prefix, name colour (nick_color, the team colour when empty) and message colour (message_color) come from CS2-Tags' tags.json, picked the way CS2-Tags picks them: SteamID64, then the first #group/@permission key in file order, then everyone. A player with no prefix shows as >[Kalus → me]. The recipient's name is in their own nick_color. The file is reread when it changes. No dead or team labels.

  • Dead players can message anyone.
  • Gagged or silenced players (CS2-SimpleAdmin) can't send.
  • A player who has blocked the sender isn't messaged, and the sender is told so. Staff get through.
  • One message per CooldownSeconds, at most MaxMessageLength characters.

Configuration

configs/plugins/Whisper/Whisper.json, written on first load:

Setting Default Meaning
History true Keep each message in wh_messages, see below
Open, Arrow, Me, Close {Default}>[, {Default}→, {Default}me, {Default}] The parts of the line around the names. Colour tags as in tags.json
TagsFile configs/plugins/CS2-Tags/tags.json Relative to addons/counterstrikesharp/
CooldownSeconds 1
MaxMessageLength 200
MaxBlocks 100 Per player
StaffPermission @css/generic Gets through blocks and can find hidden admins
SpoolMaxEntries 20000 Writes kept on disk while the database is down

Storage

Everything is in CS2-SimpleAdmin's MySQL database, over its connection string (from its API), in tables created on first load and tracked in wh_migrations. All times are UTC.

History

With History on, every message is a row in wh_messages, sent or not:

channel What
all, team Normal chat, including !// commands (result command) other than the ones below
pm /pm, /w and /r
staff, to_staff @ team chat, from staff (@css/chat) or from a player to staff
css_say, css_asay, css_psay, css_csay, css_hsay, css_cssay SimpleAdmin's say commands, typed in console, sent over RCON (the web panel too), or as !asay and the like in chat. @ in all chat from staff is css_say, as SimpleAdmin runs it

Each row has when (sent_at), server_id (SimpleAdmin's), map, the sender's SteamID64, name, team (0 none, 1 spectator, 2 T, 3 CT) and whether alive (all NULL and "Console" for the server console), the message, and the result: sent, gagged (stopped by a gag or silence; @ team chat gets through one), command, or for pm blocked, cooldown, too_long, no_target, ambiguous or group_target. PMs also have the recipient's SteamID64, name, team and whether alive, and target as typed (css_psay has target too). Staff commands are logged as typed, so one the sender wasn't allowed to use still says sent.

Chat is seen by a catch-all command listener added in Load. CSS runs catch-alls before any per-command listener (CS2-Tags' say, for one), in the order they were added, and stops at the first that returns Stop. CS2-SimpleAdmin adds its catch-all (which stops gagged players and handles @) in OnAllPluginsLoaded, after every plugin's Load, so Whisper always sees a line before it's stopped or rewritten. Keep that in mind if SimpleAdmin ever moves its listener into Load.

css_whisper_history off stops it at once and saves the setting to Whisper.json; rows already kept stay. Writes go in order on a background task and spool to plugins/Whisper/spool.jsonl while the database is down.

SELECT sent_at, map, channel, sender_name, sender_steamid64, sender_team, sender_alive,
       recipient_name, message, result
FROM wh_messages ORDER BY sent_at DESC LIMIT 50;

Blocks

wh_blocks: blocker, blocked, the blocked player's name when blocked (empty for an offline SteamID64), and when. Kept whatever History says. A player's list is read when they join.

Building and releasing

../../build.sh from this folder builds into compiled/Whisper/. lib/CS2-SimpleAdminApi.dll is a compile-only copy of the one SimpleAdmin installs in shared/.

./release.sh v<ModuleVersion> (Forgejo token from FORGEJO_TOKEN or ../../.forgejo-token) builds from the committed source, tags it, and publishes Whisper-<tag>.tar.gz (laid out like game/csgo/) on git.zio.sh. The server installs it from there (WHISPER_VERSION in the server repo's update_plugins.sh).