Generated reference. This page mirrors
Code/Chat/README.md, this module's source-of-truth documentation (Standards/02_DOCUMENTATION_STANDARDS.md §1). Edit it there, not here -- this file is regenerated on every docs build and any local edit is silently overwritten.
Chat¶
Purpose. Channel routing — recipient computation, permission/cooldown/cost gates, and a typed delivery event. See 19_CHAT_FRAMEWORK.md.
Responsibilities.
- ChatChannel — Ooc, GlobalAction, AdminChat, ModeratorChat, Radio, Advert, Pm.
The six legacy channels that are server-wide or group-filtered rather than
proximity-filtered, plus Pm (Milestone 12).
- IChatService / ChatRouter — SendAsync(Character, ChatChannel, string): computes the
real recipient list per channel, enforces cooldowns (Ooc, Advert) and cost (Advert,
via IEconomyService), and permission- or job-group-filters recipients (AdminChat,
ModeratorChat, Radio). Refuses ChatChannel.Pm outright (throws — a caller-code bug,
never player-triggerable): Pm has no roster-computed recipient set, so routing it through
SendAsync would otherwise silently broadcast a "private" message to everyone active.
SendDirectAsync(Character sender, Character recipient, string text) (Milestone 12) is
Pm's real send path — same mute/empty/length checks as SendAsync, but the recipient is
the caller-supplied target. ChatRouter is the one implementation of both.
- ChatMessageSent — published after every successful send, carrying the computed
recipients — see
19_CHAT_FRAMEWORK.md §5.
- ChatNetworkComponent — subscribes to ChatMessageSent host-side, resolves Recipients to
Connections via Character.FindConnection(), and delivers a ReceiveChatLine RPC scoped
to exactly those connections via Rpc.FilterInclude. One scene-level singleton, not a
per-character component — see
19_CHAT_FRAMEWORK.md §5.
- Ui/ChatPanel.razor / Ui/ChatRootComponent.cs — the chat box itself: message log, text
entry, /command autocomplete against ICommandRegistry, and the toggle (Input.Pressed
("chat")) that shows/hides it. Plain text with no leading / is sent as /ooc
automatically.
- /ooc, /globalaction, /a, /m, /radio, /advert, /pm — registered against
ICommandRegistry by ChatModule.Ready().
- /pm <name> <text...> (Milestone 12) — a private, one-to-one message. No permission
required (matching legacy's own "b" access flag). Resolves its target via
ICharacterService.FindActiveByName (Code/Characters/ICharacterService.cs), the
target-resolution-by-name capability this used to block on — see
19_CHAT_FRAMEWORK.md §1.
IChatService.SendDirectAsync(sender, recipient, text) is the underlying send: same
mute/empty/length checks as SendAsync, but the recipient is the resolved target, not
computed from a ChatChannel. arguments[0] is a single whitespace-delimited token, so a
character whose name contains a space cannot be targeted today — named, not solved, in
ChatModule.PmAsync's own doc comment.
- Mute enforcement (Milestone 11) — SendAsync's first real check, ahead of the
empty/length checks: loads the sender's Account via IAccountService and refuses if
Moderation.IsActive at ModerationStatus.Muted, on every channel. See
22_PLAYER_PRESENCE_AND_ADMIN_TOOLS.md §6
and Admin's /mute//unmute.
Not responsible for.
- Default IC speech, /y, /w, /me, /action, /looc. All proximity-filtered.
Applejack.Movement's PawnComponent/IPawnLocator (ADR-0007)
landed this same milestone, so the Transform/pawn-position binding this used to block on
now exists — but the proximity-filtering logic itself (a radius, message truncation by
distance) is not built on top of it yet. Same gap Code/World/README.md and
Code/Crime/README.md used to name for the same reason; both should be revisited too.
- /note — a physical item, Items/Inventory's concern, not a chat channel.
/details — character data display, not routing. Out of scope by definition.
- Notification levels (water drip / buzzer / bip / tic) — a HUD/UI concern, not routing.
- The command registry and dispatch itself — that's Commands
(Code/Commands/README.md).
Dependencies. Core (IServiceRegistry, IServiceResolver, IEventBus, IGameLog,
IClock), Character (Character, ICharacterService.GetAllActive, ICharacterService.
FindActiveByName for /pm's target resolution, IAccountService, for the mute check),
Commands (ICommandRegistry, CommandDefinition), Jobs (IJobService, IJobRegistry,
TeamGroup, for Radio's filter), Economy (IEconomyService, for Advert's cost). Not
Persistence of its own — cooldowns are in-memory only (IAccountService's own
accounts/{steamId} persistence belongs to Character, not this module); see
19_CHAT_FRAMEWORK.md §4.
Public API.
- IChatService.SendAsync(Character sender, ChatChannel channel, string text),
.SendDirectAsync(Character sender, Character recipient, string text).
- ChatChannel, ChatMessageSent.
Events published. ChatMessageSent.
Persistence. None — cooldowns reset on server restart, deliberately (a spam guard, not game state that must survive one).
Future improvements.
- IC speech, yell, whisper, emote, action, and local OOC, once a Transform/pawn-position
binding exists for a Character.
- /command help/usage inline in ChatPanel's autocomplete beyond a simple name-prefix match
(fuzzy matching, argument hints as you type past the command name).