From 1c38edaae4638428277740d629998c82f418320d Mon Sep 17 00:00:00 2001 From: stoneharry Date: Tue, 17 Jun 2025 17:43:49 +0200 Subject: [PATCH] Core/Chat: Apply chat flood control to addon messages as well (cherry picked from commit 5384fc194f9061bbac314abb66a9bac88aaaf760) --- src/server/game/Entities/Player/Player.cpp | 43 ++++++++++++-------- src/server/game/Entities/Player/Player.h | 20 ++++++--- src/server/game/Handlers/ChatHandler.cpp | 15 ++++++- src/server/game/Server/WorldSession.cpp | 5 +++ src/server/game/Server/WorldSession.h | 1 + src/server/game/World/World.cpp | 2 + src/server/game/World/World.h | 2 + src/server/worldserver/worldserver.conf.dist | 17 +++++++- 8 files changed, 79 insertions(+), 26 deletions(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 29a6ae8d43..527d4ac2c2 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -146,9 +146,6 @@ uint64 const MAX_MONEY_AMOUNT = 9999999999ULL; Player::Player(WorldSession* session): Unit(true) { - m_speakTime = 0; - m_speakCount = 0; - m_objectType |= TYPEMASK_PLAYER; m_objectTypeId = TYPEID_PLAYER; @@ -19903,39 +19900,49 @@ void Player::outDebugValues() const /*** FLOOD FILTER SYSTEM ***/ /*********************************************************/ -void Player::UpdateSpeakTime() +void Player::UpdateSpeakTime(ChatFloodThrottle::Index index) { // ignore chat spam protection for GMs in any mode if (GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHAT_SPAM)) return; - time_t current = GameTime::GetGameTime(); - if (m_speakTime > current) + uint32 limit; + uint32 delay; + switch (index) { - uint32 max_count = sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_COUNT); - if (!max_count) + case ChatFloodThrottle::REGULAR: + limit = sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_COUNT); + delay = sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_DELAY); + break; + case ChatFloodThrottle::ADDON: + limit = sWorld->getIntConfig(CONFIG_CHATFLOOD_ADDON_MESSAGE_COUNT); + delay = sWorld->getIntConfig(CONFIG_CHATFLOOD_ADDON_MESSAGE_DELAY); + break; + default: + return; + } + + time_t current = GameTime::GetGameTime(); + if (m_chatFloodData[index].Time > current) + { + if (!limit) return; - ++m_speakCount; - if (m_speakCount >= max_count) + ++m_chatFloodData[index].Count; + if (m_chatFloodData[index].Count >= limit) { // prevent overwrite mute time, if message send just before mutes set, for example. time_t new_mute = current + sWorld->getIntConfig(CONFIG_CHATFLOOD_MUTE_TIME); if (GetSession()->m_muteTime < new_mute) GetSession()->m_muteTime = new_mute; - m_speakCount = 0; + m_chatFloodData[index].Count = 0; } } else - m_speakCount = 1; + m_chatFloodData[index].Count = 1; - m_speakTime = current + sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_DELAY); -} - -bool Player::CanSpeak() const -{ - return GetSession()->m_muteTime <= time (nullptr); + m_chatFloodData[index].Time = current + delay; } /*********************************************************/ diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 43616fe0fa..a7a6ab76c3 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2108,9 +2108,20 @@ class TC_GAME_API Player : public Unit, public GridObject /*** FLOOD FILTER SYSTEM ***/ /*********************************************************/ - void UpdateSpeakTime(); - bool CanSpeak() const; - void ChangeSpeakTime(int utime); + struct ChatFloodThrottle + { + enum Index + { + REGULAR = 0, + ADDON = 1, + MAX + }; + + time_t Time = 0; + uint32 Count = 0; + }; + + void UpdateSpeakTime(ChatFloodThrottle::Index index); /*********************************************************/ /*** VARIOUS SYSTEMS ***/ @@ -2502,8 +2513,7 @@ class TC_GAME_API Player : public Unit, public GridObject uint32 m_team; uint32 m_nextSave; - time_t m_speakTime; - uint32 m_speakCount; + std::array m_chatFloodData; Difficulty m_dungeonDifficulty; Difficulty m_raidDifficulty; Difficulty m_raidMapDifficulty; diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 3cb9445a5d..70a92268fc 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -212,13 +212,16 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) lang = ModLangAuras.front()->GetMiscValue(); } - if (!sender->CanSpeak()) + if (!CanSpeak()) { std::string timeStr = secsToTimeString(m_muteTime - GameTime::GetGameTime()); SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); recvData.rfinish(); // Prevent warnings return; } + + if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND) + sender->UpdateSpeakTime(Player::ChatFloodThrottle::REGULAR); } } else @@ -651,6 +654,14 @@ void WorldSession::HandleAddonMessagechatOpcode(WorldPacket& recvData) return; } + if (!CanSpeak()) + { + recvData.rfinish(); + return; + } + + sender->UpdateSpeakTime(Player::ChatFloodThrottle::ADDON); + switch (type) { case CHAT_MSG_BATTLEGROUND: @@ -727,7 +738,7 @@ void WorldSession::HandleSendTextEmoteOpcode(WorldPackets::Chat::SendTextEmote& if (!GetPlayer()->IsAlive()) return; - if (!GetPlayer()->CanSpeak()) + if (!CanSpeak()) { std::string timeStr = secsToTimeString(m_muteTime - GameTime::GetGameTime()); SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index ce20d2249f..29b5930951 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -748,6 +748,11 @@ void WorldSession::SendNotification(uint32 string_id, ...) } } +bool WorldSession::CanSpeak() const +{ + return m_muteTime <= GameTime::GetGameTime(); +} + char const* WorldSession::GetTrinityString(uint32 entry) const { return sObjectMgr->GetTrinityString(entry, GetSessionDbLocaleIndex()); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index dcea02a615..19ae1465b3 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -628,6 +628,7 @@ class TC_GAME_API WorldSession void DoLootRelease(ObjectGuid lguid); // Account mute time + bool CanSpeak() const; time_t m_muteTime; // Locales diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 5a1b85c00f..59c9490ee9 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1187,6 +1187,8 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_CHATFLOOD_MESSAGE_COUNT] = sConfigMgr->GetIntDefault("ChatFlood.MessageCount", 10); m_int_configs[CONFIG_CHATFLOOD_MESSAGE_DELAY] = sConfigMgr->GetIntDefault("ChatFlood.MessageDelay", 1); + m_int_configs[CONFIG_CHATFLOOD_ADDON_MESSAGE_COUNT] = sConfigMgr->GetIntDefault("ChatFlood.AddonMessageCount", 100); + m_int_configs[CONFIG_CHATFLOOD_ADDON_MESSAGE_DELAY] = sConfigMgr->GetIntDefault("ChatFlood.AddonMessageDelay", 1); m_int_configs[CONFIG_CHATFLOOD_MUTE_TIME] = sConfigMgr->GetIntDefault("ChatFlood.MuteTime", 10); m_bool_configs[CONFIG_EVENT_ANNOUNCE] = sConfigMgr->GetBoolDefault("Event.Announce", false); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 63923cfc22..856f44eea8 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -295,6 +295,8 @@ enum WorldIntConfigs : uint8 CONFIG_EXPANSION, CONFIG_CHATFLOOD_MESSAGE_COUNT, CONFIG_CHATFLOOD_MESSAGE_DELAY, + CONFIG_CHATFLOOD_ADDON_MESSAGE_COUNT, + CONFIG_CHATFLOOD_ADDON_MESSAGE_DELAY, CONFIG_CHATFLOOD_MUTE_TIME, CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY, CONFIG_CREATURE_FAMILY_FLEE_DELAY, diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 835015db4e..43ad099497 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1931,9 +1931,24 @@ ChatFlood.MessageCount = 10 ChatFlood.MessageDelay = 1 +# +# ChatFlood.AddonMessageCount +# Description: Chat flood protection, number of addon messages before player gets muted. +# Default: 100 - (Enabled) +# 0 - (Disabled) + +ChatFlood.AddonMessageCount = 100 + +# +# ChatFlood.AddonMessageDelay +# Description: Time (in seconds) between addon messages to be counted into ChatFlood.AddonMessageCount. +# Default: 1 + +ChatFlood.AddonMessageDelay = 1 + # # ChatFlood.MuteTime -# Description: Time (in seconds) characters get muted for violating ChatFlood.MessageCount. +# Description: Time (in seconds) characters get muted for violating ChatFlood.MessageCount / ChatFlood.AddonMessageCount. # Default: 10 ChatFlood.MuteTime = 10