diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index a0a06f1c4..3e0775842 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -1880,9 +1880,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 diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ebf6681ea..4ad16ce33 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -153,9 +153,6 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this) #pragma warning(default:4355) #endif - m_speakTime = 0; - m_speakCount = 0; - m_objectType |= TYPEMASK_PLAYER; m_objectTypeId = TYPEID_PLAYER; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 5f9cd4f68..73a652459 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2256,9 +2256,21 @@ public: /*** FLOOD FILTER SYSTEM ***/ /*********************************************************/ - void UpdateSpeakTime(uint32 specialMessageLimit = 0); + struct ChatFloodThrottle + { + enum Index + { + REGULAR = 0, + ADDON = 1, + MAX + }; + + time_t Time = 0; + uint32 Count = 0; + }; + + void UpdateSpeakTime(ChatFloodThrottle::Index index); [[nodiscard]] bool CanSpeak() const; - void ChangeSpeakTime(int utime); /*********************************************************/ /*** VARIOUS SYSTEMS ***/ @@ -2695,8 +2707,7 @@ public: uint16 m_additionalSaveTimer; // pussywizard uint8 m_additionalSaveMask; // pussywizard uint16 m_hostileReferenceCheckTimer; // pussywizard - 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/Entities/Player/PlayerMisc.cpp b/src/server/game/Entities/Player/PlayerMisc.cpp index c8a91f0b9..173b366f7 100644 --- a/src/server/game/Entities/Player/PlayerMisc.cpp +++ b/src/server/game/Entities/Player/PlayerMisc.cpp @@ -26,34 +26,44 @@ /*** FLOOD FILTER SYSTEM ***/ /*********************************************************/ -void Player::UpdateSpeakTime(uint32 specialMessageLimit) +void Player::UpdateSpeakTime(ChatFloodThrottle::Index index) { // ignore chat spam protection for GMs in any mode if (!AccountMgr::IsPlayerAccount(GetSession()->GetSecurity())) return; - time_t current = GameTime::GetGameTime().count(); - if (m_speakTime > current) + uint32 limit, delay; + switch (index) { - uint32 max_count = specialMessageLimit ? specialMessageLimit : sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_COUNT); - if (!max_count) - return; - - ++m_speakCount; - if (m_speakCount >= max_count) + case ChatFloodThrottle::ADDON: + limit = sWorld->getIntConfig(CONFIG_CHATFLOOD_ADDON_MESSAGE_COUNT); + delay = sWorld->getIntConfig(CONFIG_CHATFLOOD_ADDON_MESSAGE_DELAY); + break; + case ChatFloodThrottle::REGULAR: + limit = sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_COUNT); + delay = sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_DELAY); + [[fallthrough]]; + default: + return; + } + time_t current = GameTime::GetGameTime().count(); + if (m_chatFloodData[index].Time > current) + { + ++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); + m_chatFloodData[index].Time = current + delay; } bool Player::CanSpeak() const diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 025b9a7cc..5d0642fca 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -194,10 +194,8 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; } } - // LANG_ADDON should not be changed nor be affected by flood control else { - uint32 specialMessageLimit = 0; // send in universal language if player in .gmon mode (ignore spell effects) if (sender->IsGameMaster()) lang = LANG_UNIVERSAL; @@ -218,20 +216,12 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) // allow two side chat at group channel if two side group allowed if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) lang = LANG_UNIVERSAL; - - specialMessageLimit = 35; break; case CHAT_MSG_GUILD: case CHAT_MSG_OFFICER: // allow two side chat at guild channel if two side guild allowed if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) lang = LANG_UNIVERSAL; - - specialMessageLimit = 15; - break; - case CHAT_MSG_WHISPER: - if (sender->getLevel() >= 80) - specialMessageLimit = 15; break; } } @@ -242,7 +232,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND) - sender->UpdateSpeakTime(specialMessageLimit); + sender->UpdateSpeakTime(lang == LANG_ADDON ? Player::ChatFloodThrottle::ADDON : Player::ChatFloodThrottle::REGULAR); } std::string to, channel, msg; @@ -344,6 +334,11 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } } + else + { + ++_addonMessageReceiveCount; + } + sScriptMgr->OnBeforeSendChatMessage(_player, type, lang, msg); switch (type) @@ -726,7 +721,7 @@ void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData) if (!GetPlayer()->IsAlive()) return; - GetPlayer()->UpdateSpeakTime(); + GetPlayer()->UpdateSpeakTime(Player::ChatFloodThrottle::REGULAR); if (!GetPlayer()->CanSpeak()) { diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 617c106a6..2849c953e 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -130,6 +130,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr updater is of type MapSessionFilter { diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index ea2375a9f..7aa9f6e12 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -1176,6 +1176,9 @@ private: // Packets cooldown time_t _calendarEventCreationCooldown; + // Addon Message count for Metric + std::atomic _addonMessageReceiveCount; + CircularBuffer> _timeSyncClockDeltaQueue; // first member: clockDelta. Second member: latency of the packet exchange that was used to compute that clockDelta. int64 _timeSyncClockDelta; void ComputeNewClockDelta(); diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h index 0544a463d..d11cb91ae 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -267,6 +267,8 @@ enum WorldIntConfigs 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_EVENT_ANNOUNCE, CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY, diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 9702172a0..d4a4a2b89 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1022,6 +1022,8 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_CHATFLOOD_MESSAGE_COUNT] = sConfigMgr->GetOption("ChatFlood.MessageCount", 10); m_int_configs[CONFIG_CHATFLOOD_MESSAGE_DELAY] = sConfigMgr->GetOption("ChatFlood.MessageDelay", 1); + m_int_configs[CONFIG_CHATFLOOD_ADDON_MESSAGE_COUNT] = sConfigMgr->GetOption("ChatFlood.AddonMessageCount", 100); + m_int_configs[CONFIG_CHATFLOOD_ADDON_MESSAGE_DELAY] = sConfigMgr->GetOption("ChatFlood.AddonMessageDelay", 1); m_int_configs[CONFIG_CHATFLOOD_MUTE_TIME] = sConfigMgr->GetOption("ChatFlood.MuteTime", 10); m_bool_configs[CONFIG_CHAT_MUTE_FIRST_LOGIN] = sConfigMgr->GetOption("Chat.MuteFirstLogin", false); m_int_configs[CONFIG_CHAT_TIME_MUTE_FIRST_LOGIN] = sConfigMgr->GetOption("Chat.MuteTimeFirstLogin", 120);