Skip to content

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. - ChatChannelOoc, 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 / ChatRouterSendAsync(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).