# Whisper Private messages between players, for CounterStrikeSharp 1.0.376 (net10.0), alongside CS2-SimpleAdmin and CS2-Tags. ## Commands | Chat | Console | What | |---|---|---| | `/pm `, `/w` | `css_pm`, `css_w` | Send a private message | | `/r ` | `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 ` | `css_unblock` | Remove that block | | | `css_whisper_history ` | `@css/root` and the server console: see [History](#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. ```sql 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` (Forgejo token from `FORGEJO_TOKEN` or `../../.forgejo-token`) builds from the committed source, tags it, and publishes `Whisper-.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`).