All notable changes to this project will be documented in this file.
PlayerUtils.QueryMatchesPlayer passed the user-supplied query string directly as a regex pattern; names or queries containing regex metacharacters (e.g. [, (, +, .) would throw ArgumentException and abort the relay path entirely. The Contains check is now evaluated first (unchanged behaviour), and Regex.IsMatch is called only as a fallback wrapped in a try-catch so an invalid pattern skips the regex step instead of throwing.TextChannelManagerPatch now uses text.Trim().StartsWith("hush:") so leading whitespace in a relay message does not cause the sentinel to be missed.PlayerLists.IsAdmin) re-enabled; admins can now issue relay commands in addition to whitelisted delegates.ExecuteRelay calls are now wrapped in a try-catch so any unhandled exception logs a full error instead of silently escaping the Harmony prefix.hush:tmute:) now accept a player name query in place of a raw Steam ID64. If the target field is not a valid Steam ID64 (SteamUtils.IsSteamID), it is resolved via PlayerUtils.FindPlayerByQuery before execution. Unresolvable queries are rejected with a warning.RelayExecutor - relay business logic extracted from TextChannelManagerPatch into a standalone injectable class. All game-API dependencies (mute manager, ban, name resolution, notifications) are injected via constructor, making the relay logic fully unit-testable./hushunmute is no longer host-only: whitelisted delegates and mod admins can now relay unmute requests to the host via hush:unmute:<target> sentinel, matching the existing tmute/ban relay pattern.PlayerUtils.FindPlayerByQuery before execution; unresolvable queries are rejected with a warning./hushlogverbose (/hlv) - toggle verbose BepInEx logging for Hush at runtime. Off by default; when enabled, debug-level traces (mute checks, relay paths, save/load messages) are emitted to the log.Hush.Tests project with 81 unit tests covering ChatFilterManager, PlayerMuteManager, RelayParser, and DurationFormatter.hush: sentinel messages. If a sentinel leaks to a client it will now display in chat as a visible indicator that the server-side intercept failed.RelayParser / DurationFormatter classes (no behaviour change).BanManager class: centralises all ban operations (add, add offline, remove, list) on top of the game's DataManager.BanData./hushban <player> (/hb) - ban an online player. Host executes directly; whitelisted delegates relay the request to the host and also add the player to their own local ban list./hushbanoffline <steamid> <nickname> (/hbo) - ban a player by Steam ID without them being online (host only)./hushunban <player|steamid> (/hub) - remove a ban; accepts player query or raw Steam ID for offline removal (host only)./hushgetbans (/hgb) - list all banned players (host only)./hushban to the host in the same way as timed mutes./hushversion (/hv) commandhush:tmute: relay/hushtmute. Delegates send a hidden sentinel message; the host validates and executes the mute server-side - the sentinel is never visible to other clients./hushdelegateadd <player> (/hdda) - add a player to the mute-delegate whitelist (host only)./hushdelegateremove <player> (/hddr) - remove a player from the whitelist; accepts a raw Steam ID for offline players (host only)./hushdelegatelist (/hddl) - list all current delegates (host only)./hushtmute is no longer host-only: whitelisted delegates may use it and their request is relayed to the host for execution./hushmute <player> - permanently mute a player by name or Steam ID suffix./hushtmute <player> <duration> - timed mute with ISO 8601 / hh:mm:ss duration (e.g. 10m, 1h30m, 30s)./hushunmute <player> - remove a permanent or timed mute. Accepts Steam ID for offline players./hushgetmutes - list all currently muted players with their expiry time.BepInEx/config/com.andrewlin.ontogether.hush.mutes.json; timed mute expiry times are preserved across game restarts.ChatFilterManager with two modes: Censor (replace matched text with asterisks) and Block (suppress the entire message).(?i), \b, etc.).BepInEx/config/AndrewLin.Hush.filter.json; updated automatically on every mutation.Filter > Action (Censor or Block), live-reload supported via ConfigurationManager.| Command | Description |
|---|---|
/hushaddword <word> |
Add a literal word |
/hushremoveword <word> |
Remove a literal word |
/hushgetwords |
List all words |
/hushaddpattern <regex> |
Add a regex pattern |
/hushremovepattern <regex> |
Remove a regex pattern |
/hushgetpatterns |
List all patterns |
/hushtoggle |
Toggle the filter on or off |
/hushfilteraction <action> |
Set the filter action (Censor or Block) |