Skip to content

Add /w whispers delivered to one player at any distance#17

Merged
Julian-adv merged 1 commit into
Julian-adv:masterfrom
treestar84:whisper-command
Jul 23, 2026
Merged

Add /w whispers delivered to one player at any distance#17
Julian-adv merged 1 commit into
Julian-adv:masterfrom
treestar84:whisper-command

Conversation

@treestar84

@treestar84 treestar84 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Add /w whispers delivered to one player at any distance

Implements the TODO item: "귓속말(DM) 기능" (doc/TODO.md)

Demo

whisper demo

Three clients side by side. Miru's normal chat reaches everyone nearby; her /w Rica whisper reaches only Rica — Nami, standing right next to them, sees nothing. Rica replies with /w and the exchange stays private.

Design

Whispers ride the existing chat path end to end:

  • Server-side parsing: /w <name> <message> (alias /whisper) is parsed in send_chat_message next to /who and /escape, with the syntax defined once in parse_whisper_command following the parse_notice_command pattern. Because it's plain chat text, the agent-client gets whispers for free through its existing say action — no new client message, same protocol for humans and agents.
  • ServerMessage::WhisperMessage { from, to, message } carries names instead of ids: whisper ignores distance, so either end may be outside the other's AOI where an id resolves to nobody client-side. It is delivered only to the target plus an echo to the sender.
  • An exact spelling always wins. Names are UNIQUE only case-sensitively ("Rica" and "rica" can coexist), so case-insensitive matching (/w rica) is a convenience that applies only while it is unambiguous — with several case variants online, the sender is asked to spell the name exactly rather than risk a private message reaching a near-miss. Names never contain spaces, so /w <name> <rest> parses unambiguously.
  • Errors go only to the sender — unknown name, missing message, self-whisper each get a private reply; a malformed whisper never leaks into local chat.
  • Like regular chat, whisper content stays out of logs (F-012) — and so does the recipient: who talks to whom is metadata worth the same protection. Only from/len are logged.
  • Adding a ServerMessage variant changes the wire shape, so PROTOCOL_VERSION bumps to 3 (per the bump-on-shape-change rule in shared/src/lib.rs).

Client: whispers render in purple as From Miru: / To Rica:, with no overhead bubble — a whisper is private. /w and /whisper join tab completion.

Agent-client: an incoming whisper classifies as Urgent (the echo of your own is Noise), reaches the LLM as a [Whisper] name: message event, and the system prompt explains how to answer one. This is groundwork for the "전언 시스템" idea — players can already whisper the resident NPCs.

Testing

  • New server tests: parse cases (/w, /whisper, /who non-collision, missing parts), delivery to a target 500m away with echo + no bystander + no broadcast leak (mixed-case name, canonical to), coexisting case-variant names (exact spelling wins, ambiguous spelling is refused and delivered to no one), and each error path replying only to the sender.
  • Full workspace suite passes; cargo fmt / cargo clippy (0 warnings) / npm run check / npm run lint / npm run test (279 client tests) all clean.
  • Verified end-to-end with three local clients (the GIF above), including /w rica lowercase, unknown-name and missing-message replies, /who regression, and tab completion cycling /w/whisper.

Whispers ride the existing chat path: the server parses "/w <name>
<message>" (alias /whisper) in send_chat_message like /who, so the web
client and the agent-client both get the feature through the plain say
action with no new client message.

A new WhisperMessage carries names instead of ids: whisper ignores
distance, so either end may be outside the other's AOI where an id
resolves to nobody client-side. It goes only to the target plus an
echo to the sender; parse failures answer with a usage line instead of
leaking the attempt into local chat. An exact spelling always wins —
names are UNIQUE only case-sensitively, so case-insensitive matching
is a convenience that applies only while it is unambiguous; otherwise
the sender is asked to spell the name exactly. Like regular chat, the
content stays out of logs (F-012), and so does the recipient — who
talks to whom is metadata worth the same protection.

Adding a ServerMessage variant changes the wire shape, so
PROTOCOL_VERSION bumps to 3.

- Web client renders whispers in purple ("From X" / "To X"), with no
  overhead bubble — a whisper is private
- /w and /whisper join the tab-completion list
- agent-client classifies an incoming whisper as Urgent and feeds it
  to the LLM as a [Whisper] event; the system prompt explains how to
  answer one

Closes the "귓속말(DM) 기능" TODO item.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Julian-adv
Julian-adv merged commit 086391e into Julian-adv:master Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants