Moderation
Muting and unmuting players in voice chat — timed and permanent mutes, reasons, a server-wide mute, and what a muted player sees
這一頁還沒有翻譯,以下顯示英文原文。
A mute stops a player talking. Their microphone, soundboard, instrument and group audio are all dropped at the relay, and nothing about what they hear changes.
That asymmetry is the whole design. Someone being moderated has to be able to hear what is being said to them and about them; a mute that also deafened would be a disconnection with extra steps, and it would leave them with no idea why.
This replaces revoking socketsvc.speak
Before these commands existed, the only way to silence someone was to take the socketsvc.speak node away in a permissions plugin. That is permanent, carries no reason, tells the player nothing at all, and needs an operator who can edit permissions. socketsvc.speak is still the right tool for a standing policy — "this rank does not get voice" — and a mute is the right tool for a person who is doing something now.
Commands
| Command | Purpose |
|---|---|
/ssvc-server mute <player> [duration] [reason...] | Mutes them. With no duration, until somebody lifts it |
/ssvc-server unmute <player> | Lifts an individual mute |
/ssvc-server mutes | Lists everybody currently muted, with reasons, who issued each and how long is left |
/ssvc-server mute-all <on|off> | Silences everybody without socketsvc.mute.exempt |
All four need socketsvc.admin.mute on top of the socketsvc.admin that gates /ssvc-server itself. Both default to op, so an unconfigured server behaves as though the extra node were not there — it exists so moderation can be handed to people who are not being handed the rest of the console.
> /ssvc-server mute Alex 2h shouting in spawn
Muted Alex in voice chat for 2h, reason: shouting in spawn
> /ssvc-server mutes
SocketSVC voice mutes: 1
Alex - 1h 58m left, by Steve, reason: shouting in spawn
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
> /ssvc-server unmute Alex
Alex can talk in voice chat again.Durations
30s, 45m, 2h, 7d, 1w, or several run together as 2h30m. perm, permanent and forever mean a mute that stands until somebody lifts it, which is also what you get by leaving the duration out.
A bare number is deliberately not a duration. Whether mute Alex 30 means thirty seconds or thirty minutes is not something anybody should have to guess, and a reason beginning with a number is far more likely than either. A trailing run with no unit — 2h30 — is refused for the same reason: taking the 2h and dropping the 30 would mute for a different length than was asked for.
Whether the word after the name is a duration or the first word of the reason is decided by whether it parses as one, so a reason really starting 5m loses that word. The reply always says which duration and which reason were understood, rather than leaving you to find out from the player.
Muting somebody who has logged off
People leave when a moderator turns up, so this is the ordinary case rather than the exception.
On Paper, a name that server has seen before resolves from the profile cache, so mute Alex 1d works whether or not Alex is online. A name it has never seen is reported as unknown.
On the server mods a name only resolves while that player is online. Either way both platforms accept a raw UUID, and /ssvc-server mutes prints the UUID under every name for exactly that — copy it out of the list to unmute somebody who is not around.
Mute-all
mute-all on silences everybody who does not hold socketsvc.mute.exempt — for an announcement, an event, or a room that has got out of hand. It is not a config setting; it is a switch you flip and flip back, and it survives a restart like any other mute, because a restart in the middle of an event should not un-silence the room.
Individual mutes are unaffected by it in both directions: mute-all off does not lift them, and unmuting one person does not turn it off.
What a muted player sees
Two things, because either on its own is not enough.
An action-bar notice the moment they try to talk, at most once every five seconds:
You are muted in voice chat for another 1h 58m: shouting in spawnAnd a persistent HUD indicator — the crossed-out microphone with Muted by server beside it, and the time left when the mute is timed. The words matter: without them a silenced player sees the same crossed-out microphone their own mute button produces, reaches for that button, and learns nothing.
Older clients see only the notice
The HUD indicator needs a client new enough to understand the SSVC_MUTE_V1 message (Voice protocol). An older one ignores the line, exactly as it ignores any text message it does not recognise, and is left with the action-bar notice — which is what it would have had anyway. Nothing about the mute itself depends on the client.
Permissions
| Node | Default | Purpose |
|---|---|---|
socketsvc.admin.mute | op | Use the four commands above |
socketsvc.mute.exempt | op | Keep talking through mute-all, and cannot be muted individually |
socketsvc.mute.exempt bypasses only the server-wide mute. An individual mute is an explicit decision somebody made about that player and is not undone by a permission node — /ssvc-server mute refuses to issue one against an exempt player in the first place, and says so. The alternative would be a mute sitting in the list doing nothing, which is the worst of both.
Like every other SocketSVC node it is read once per tick, and a player who has just joined and has not been ticked yet is treated as not exempt — an unticked player must not briefly talk over a room somebody has just silenced.
Where mutes are stored
| Server side | File |
|---|---|
| Paper | plugins/SocketSVC/mutes.txt |
| Fabric/Quilt, NeoForge, Forge | config/socketsvc-mutes.txt |
A mute that lives only in memory is undone by logging out, so every change is written immediately. The file is written to a sibling temporary file and moved into place, so a crash mid-write leaves the previous list rather than a half-written one.
It is a plain text file and can be read, but editing it by hand is not the intended route: the server holds the same list in memory and will overwrite yours on its next change. /ssvc-server reload re-reads it, because a reload builds a replacement listener.
A mute whose time ran out while the server was down does not come back. One row that cannot be parsed is skipped and reported in the log rather than taking the rest of the file with it — one corrupt line must not hand everybody else their voice back.
For addons
SocketSvcApi and SocketSvcModApi expose the same registry the relay reads from version 3 onwards, so an addon and the audio path cannot disagree about who is silenced. See Spatial audio API.
SocketSvcApi api = /* ... */;
api.muteVoice(player, 2 * 60 * 60 * 1000L, "shouting in spawn", "AntiSpam");
boolean silenced = api.isVoiceMuted(player); // individual mute OR mute-all they are not exempt from
api.unmuteVoice(player);