Whisper/README.md
Astra c414e8a770 Whisper 0.1.0: private messages between players
/pm (/w) with names, #userid, SteamIDs, @me, @aim, @random, @randomt and
@randomct, /r to reply, and /block, /blocklist, /unblock. Lines use
CS2-Tags' rank prefixes and colours: >[[M] Kalus -> me] message. Gagged
players can't send; blocks stop everyone but staff. Messages are kept in
CS2-SimpleAdmin's database while History is on (css_whisper_history).
2026-10-05 13:13:58 +01:00

101 lines
4.8 KiB
Markdown

# 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](#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, each `/pm` and `/r`, sent or not, is a row in `wh_messages`: when (`sent_at`),
`server_id` (SimpleAdmin's), `map`, the sender's and recipient's SteamID64, name, team (0 none,
1 spectator, 2 T, 3 CT) and whether alive, the `target` as typed, the `message`, and the `result`:
`sent`, `blocked`, `gagged`, `cooldown`, `too_long`, `no_target`, `ambiguous` or `group_target`. The
recipient columns are `NULL` when no single player was found.
`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, sender_name, sender_steamid64, sender_team, sender_alive,
recipient_name, recipient_steamid64, recipient_team, recipient_alive, 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`).