From 7de6c612df82e4eb1b55473f88566049c8e48a53 Mon Sep 17 00:00:00 2001 From: Ada Date: Wed, 29 Apr 2026 14:56:26 -0400 Subject: [PATCH] Add in-game /help command for chat-command discovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Players had no way to discover what KC's chat commands were on a given server — defaulting to /home or /shop only worked if someone told them the commands existed first. Adds /help (also /commands and /?) which lists every chat-command group enabled on this server, formatted one line per group: Available commands: HOME: /home [name], /sethome , /delhome , /homes TELEPORT: /tp , /cities POINTS: /points, /signin STORE: /shop, /buy VIP: /vip TICKETS: /ticket , /ticket , /tickets BLOOD MOON: /skipbm (alias: /voteskip) Two design decisions worth flagging: - Help itself has no enable toggle. Even if every optional group is turned off, /help still works and surfaces 'all groups disabled' — which is itself useful info for the player and the admin. - Group lines respect each feature's own enable flag, so a server running without the store doesn't tell players to try /buy. - Uses settings.Prefix so non-default prefixes ('!', '.', etc.) render correctly. (Bootstrapping is still on the operator: a player who doesn't know the prefix can't reach /help in the first place. Server MOTD or welcome message handles that.) Three aliases (help / commands / ?) so different player muscle memory all hits the same handler. --- .../Features/ChatCommandService.cs | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/KitsuneCommand/Features/ChatCommandService.cs b/src/KitsuneCommand/Features/ChatCommandService.cs index 7a252c3..1b3ac4b 100644 --- a/src/KitsuneCommand/Features/ChatCommandService.cs +++ b/src/KitsuneCommand/Features/ChatCommandService.cs @@ -163,6 +163,16 @@ public bool TryHandleCommand(string playerId, int entityId, string playerName, s HandleBloodMoonVote(playerId, entityId, playerName); return true; + // ── Help / discovery ───────────────────────────────── + // Always available regardless of feature toggles. If a server + // disables every group, /help still works and just reports + // back that nothing's enabled — which is itself useful info. + case "help": + case "commands": + case "?": + HandleHelp(entityId, settings); + return true; + default: return false; // Not a recognized command } @@ -715,6 +725,67 @@ private void HandleBloodMoonVote(string playerId, int entityId, string playerNam } } + // ─── Help ────────────────────────────────────────────────────── + + /// + /// Lists the commands available to the calling player. Only enabled + /// feature groups are shown — running `/help` on a server with the + /// store turned off shouldn't tell the player to try `/buy`. + /// + /// Each Reply() is a separate `pm` to the player's chat, so we can + /// safely emit one line per group without worrying about message + /// length truncation. + /// + private void HandleHelp(int entityId, ChatCommandSettings settings) + { + var p = settings.Prefix; + Reply(entityId, "Available commands:"); + + var anyEnabled = false; + + if (settings.HomeEnabled) + { + Reply(entityId, $" HOME: {p}home [name], {p}sethome , {p}delhome , {p}homes"); + anyEnabled = true; + } + if (settings.TeleportEnabled) + { + Reply(entityId, $" TELEPORT: {p}tp , {p}cities"); + anyEnabled = true; + } + if (settings.PointsEnabled) + { + Reply(entityId, $" POINTS: {p}points, {p}signin"); + anyEnabled = true; + } + if (settings.StoreEnabled) + { + Reply(entityId, $" STORE: {p}shop, {p}buy "); + anyEnabled = true; + } + if (settings.VipEnabled) + { + Reply(entityId, $" VIP: {p}vip"); + anyEnabled = true; + } + if (settings.TicketEnabled) + { + Reply(entityId, $" TICKETS: {p}ticket , {p}ticket , {p}tickets"); + anyEnabled = true; + } + + // Blood Moon Vote has its own enable check inside the feature + // (rather than a settings.BloodMoonVoteEnabled flag here), so we + // surface it unconditionally; the feature itself replies with a + // "disabled" message if a player tries to vote while it's off. + Reply(entityId, $" BLOOD MOON: {p}skipbm (alias: {p}voteskip)"); + + if (!anyEnabled) + { + Reply(entityId, "(All optional feature groups are currently disabled on this server.)"); + } + } + // ─── Helpers ─────────────────────────────────────────────────── ///