From 8c446330c22cbfb6875b9f0f470293fed9fccc96 Mon Sep 17 00:00:00 2001 From: phyce Date: Sat, 23 May 2026 11:20:24 +0000 Subject: [PATCH] Audit ChatMessageType coverage end-to-end Goes through every value in net.runelite.api.ChatMessageType and makes sure each one is either (a) explicitly voiced and gated by a sensible config toggle, or (b) explicitly muted. Previously many types fell into the silent "didn't match" branch in onChatMessage and were dropped entirely. Bug fixes: * MODPRIVATECHAT was listed in both isChatInnerVoice and isChatOtherPlayerVoice. Inner won the if/else, so an incoming PM from a mod was spoken in the local player's voice. Removed from isChatInnerVoice so MODPRIVATECHAT now correctly uses the mod's voice via the other-player path. * CHALREQ_TRADE / CHALREQ_FRIENDSCHAT / CHALREQ_CLANCHAT were gated on requestsEnabled but never routed to any voice, so even when enabled they fell through to "didn't match" and never spoke. Added to isChatSystemVoice. Voice routing for previously-dropped types: * TRADE_SENT -> inner voice (it's your own action) * FRIENDNOTIFICATION, FRIENDSCHATNOTIFICATION, SNAPSHOTFEEDBACK, DIDYOUKNOW, LEVELUPMESSAGE -> system voice * SPAM, MODAUTOTYPER -> always muted (matches existing AUTOTYPER) Config gating consistency. System-voice types that were previously ungated now respect systemMesagesEnabled the way GAMEMESSAGE / WELCOME already do: * ENGINE, BROADCAST, IGNORENOTIFICATION, TRADE, PLAYERRELATED, TENSECTIMEOUT, SNAPSHOTFEEDBACK, CLAN_GIM_FORM_GROUP, CLAN_GIM_GROUP_WITH -> systemMesagesEnabled Dual-gating for system messages that live inside a chat channel (following the CLAN_MESSAGE precedent from PR #40): * LOGINLOGOUTNOTIFICATION, FRIENDNOTIFICATION, FRIENDSCHATNOTIFICATION -> friendsChatEnabled + systemMesagesEnabled * CLAN_CREATION_INVITATION -> clanChatEnabled + systemMesagesEnabled Single-purpose gating with new toggles: * DIDYOUKNOW -> new didYouKnow toggle (default off) * LEVELUPMESSAGE -> new levelUpMessages toggle (default off) Request-class: * TRADE_SENT -> requestsEnabled (joins the existing TRADEREQ / CHALREQ_* gate). Out of scope / follow-up: * MESBOX (dialog box / book pages) needs widget plumbing like DIALOG has - left for a separate PR. * NPC_SAY likely duplicates OverheadTextChanged - left until verified. * CLAN_GIM_FORM_GROUP / CLAN_GIM_GROUP_WITH are currently single-gated on system messages here; after PR #47 lands they could be dual-gated with groupIronmanChatEnabled. --- FEATURES.md | 1 + .../naturalspeech/SpeechEventHandler.java | 41 ++++++++++++++++++- .../configs/NaturalSpeechConfig.java | 24 +++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/FEATURES.md b/FEATURES.md index eb5d38c8..9720fb07 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -41,6 +41,7 @@ Intergrated with [Spam Filter](https://runelite.net/plugin-hub/show/spamfilter) ## 1.3.0 - Fixed numbers with commas in system messages not being read correctly +- Audit of `ChatMessageType` coverage: previously-dropped message types (challenge requests, trade sent, friend list changes, etc.) now speak; all system message types respect the System messages toggle; new "Did you know?" and "Level up messages" toggles (both off by default) ## 1.2.6 - Updated Menu event handler to work with the latest update affecting submenus diff --git a/src/main/java/dev/phyce/naturalspeech/SpeechEventHandler.java b/src/main/java/dev/phyce/naturalspeech/SpeechEventHandler.java index 0ea170b8..5475ea3f 100644 --- a/src/main/java/dev/phyce/naturalspeech/SpeechEventHandler.java +++ b/src/main/java/dev/phyce/naturalspeech/SpeechEventHandler.java @@ -199,11 +199,11 @@ public static boolean isChatInnerVoice(ChatMessage message) { case PUBLICCHAT: return Objects.equals(Text.standardize(message.getName()), getLocalPlayerUsername()); case PRIVATECHATOUT: - case MODPRIVATECHAT: case ITEM_EXAMINE: case NPC_EXAMINE: case OBJECT_EXAMINE: case TRADEREQ: + case TRADE_SENT: return true; default: return false; @@ -233,6 +233,9 @@ public static boolean isChatSystemVoice(ChatMessageType messageType) { case LOGINLOGOUTNOTIFICATION: case BROADCAST: case IGNORENOTIFICATION: + case FRIENDNOTIFICATION: + case FRIENDSCHATNOTIFICATION: + case SNAPSHOTFEEDBACK: case CLAN_MESSAGE: case CONSOLE: case TRADE: @@ -243,6 +246,11 @@ public static boolean isChatSystemVoice(ChatMessageType messageType) { case CLAN_GIM_FORM_GROUP: case CLAN_GIM_GROUP_WITH: case GAMEMESSAGE: + case DIDYOUKNOW: + case LEVELUPMESSAGE: + case CHALREQ_TRADE: + case CHALREQ_FRIENDSCHAT: + case CHALREQ_CLANCHAT: return true; default: return false; @@ -250,7 +258,12 @@ public static boolean isChatSystemVoice(ChatMessageType messageType) { } public boolean isChatMessageMuted(ChatMessage message) { + // AUTOTYPER and MODAUTOTYPER are always muted - they're the in-game + // "autotyper" mechanism we have no reason to voice. SPAM is content + // that the game (or our SpamFilter) has already flagged - don't speak it. if (message.getType() == ChatMessageType.AUTOTYPER) return true; + if (message.getType() == ChatMessageType.MODAUTOTYPER) return true; + if (message.getType() == ChatMessageType.SPAM) return true; // dialog messages are handled in onWidgetLoad if (message.getType() == ChatMessageType.DIALOG) return true; @@ -358,9 +371,35 @@ public boolean isMessageTypeDisabledInConfig(ChatMessage message) { case WELCOME: case GAMEMESSAGE: case CONSOLE: + case ENGINE: + case BROADCAST: + case IGNORENOTIFICATION: + case TRADE: + case PLAYERRELATED: + case TENSECTIMEOUT: + case SNAPSHOTFEEDBACK: + case CLAN_GIM_FORM_GROUP: + case CLAN_GIM_GROUP_WITH: + if (!config.systemMesagesEnabled()) return true; + break; + case LOGINLOGOUTNOTIFICATION: + case FRIENDNOTIFICATION: + case FRIENDSCHATNOTIFICATION: + if (!config.friendsChatEnabled()) return true; if (!config.systemMesagesEnabled()) return true; break; + case CLAN_CREATION_INVITATION: + if (!config.clanChatEnabled()) return true; + if (!config.systemMesagesEnabled()) return true; + break; + case DIDYOUKNOW: + if (!config.didYouKnowEnabled()) return true; + break; + case LEVELUPMESSAGE: + if (!config.levelUpMessagesEnabled()) return true; + break; case TRADEREQ: + case TRADE_SENT: case CHALREQ_CLANCHAT: case CHALREQ_FRIENDSCHAT: case CHALREQ_TRADE: diff --git a/src/main/java/dev/phyce/naturalspeech/configs/NaturalSpeechConfig.java b/src/main/java/dev/phyce/naturalspeech/configs/NaturalSpeechConfig.java index 3dd4cac6..c766b4c6 100644 --- a/src/main/java/dev/phyce/naturalspeech/configs/NaturalSpeechConfig.java +++ b/src/main/java/dev/phyce/naturalspeech/configs/NaturalSpeechConfig.java @@ -39,6 +39,8 @@ final class ConfigKeys { public static final String SHORTENED_PHRASES = "shortenedPhrases"; public static final String HOLD_SHIFT_RIGHT_CLICK_MENU = "holdShiftRightClickMenu"; public static final String MUTE_GRAND_EXCHANGE_NPC_SPAM = "muteGrandExchangeNpcSpam"; + public static final String DID_YOU_KNOW = "didYouKnow"; + public static final String LEVEL_UP_MESSAGES = "levelUpMessages"; } // @@ -284,6 +286,28 @@ default boolean requestsEnabled() { default boolean systemMesagesEnabled() { return true; } + + @ConfigItem( + keyName=ConfigKeys.DID_YOU_KNOW, + name="\"Did you know?\" tips", + description="Speak the periodic \"Did you know?\" tips the game shows.", + section=ttsOptionsSection, + position=13 + ) + default boolean didYouKnowEnabled() { + return false; + } + + @ConfigItem( + keyName=ConfigKeys.LEVEL_UP_MESSAGES, + name="Level up messages", + description="Speak the \"Check the skill guide\" message that fires alongside the level-up jingle.", + section=ttsOptionsSection, + position=14 + ) + default boolean levelUpMessagesEnabled() { + return false; + } // //