summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/sql/updates/pending_db_characters/rev_1638643807174948000.sql9
-rw-r--r--data/sql/updates/pending_db_world/rev_1638641366613580300.sql12
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp5
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.h4
-rw-r--r--src/server/game/Battlegrounds/BattlegroundQueue.cpp12
-rw-r--r--src/server/game/Entities/Player/Player.cpp4
-rw-r--r--src/server/game/Entities/Player/Player.h10
-rw-r--r--src/server/game/Entities/Player/PlayerSettings.cpp128
-rw-r--r--src/server/game/Entities/Player/PlayerSettings.h51
-rw-r--r--src/server/game/Entities/Player/PlayerStorage.cpp3
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp4
-rw-r--r--src/server/game/Miscellaneous/Language.h6
-rw-r--r--src/server/game/World/IWorld.h3
-rw-r--r--src/server/game/World/World.cpp37
-rw-r--r--src/server/game/World/World.h2
-rw-r--r--src/server/scripts/Commands/cs_player_settings.cpp81
-rw-r--r--src/server/scripts/Commands/cs_script_loader.cpp2
-rw-r--r--src/server/worldserver/worldserver.conf.dist15
-rw-r--r--src/test/mocks/WorldMock.h1
19 files changed, 381 insertions, 8 deletions
diff --git a/data/sql/updates/pending_db_characters/rev_1638643807174948000.sql b/data/sql/updates/pending_db_characters/rev_1638643807174948000.sql
new file mode 100644
index 0000000000..0444c1864e
--- /dev/null
+++ b/data/sql/updates/pending_db_characters/rev_1638643807174948000.sql
@@ -0,0 +1,9 @@
+INSERT INTO `version_db_characters` (`sql_rev`) VALUES ('1638643807174948000');
+
+DROP TABLE IF EXISTS `character_settings`;
+CREATE TABLE IF NOT EXISTS `character_settings` (
+ `guid` INT UNSIGNED NOT NULL,
+ `source` VARCHAR(40) NOT NULL,
+ `data` TEXT NULL,
+ PRIMARY KEY (`guid`, `source`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4 COMMENT='Player Settings';
diff --git a/data/sql/updates/pending_db_world/rev_1638641366613580300.sql b/data/sql/updates/pending_db_world/rev_1638641366613580300.sql
new file mode 100644
index 0000000000..43b31e15a3
--- /dev/null
+++ b/data/sql/updates/pending_db_world/rev_1638641366613580300.sql
@@ -0,0 +1,12 @@
+INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1638641366613580300');
+
+DELETE FROM `command` WHERE `name` IN ('settings', 'settings announcer');
+INSERT INTO `command` (`name`, `security`, `help`) VALUES
+('settings', 1, 'Syntax: .settings $subcommand\nType .setting to see the list of all available commands.'),
+('settings announcer', 1, 'Syntax: .settings announcer <type> <on/off>.\nDisables receiving announcements. Valid announcement types are: \'autobroadcast\', \'arena\' and \'bg\'');
+
+DELETE FROM `acore_string` WHERE `entry` IN (5079, 5080, 5081);
+INSERT INTO `acore_string` (`entry`, `content_default`) VALUES
+(5079, 'You must be at least level %u to disable autobroadcast messages.'),
+(5080, 'You are now receiving global %s messages.'),
+(5081, 'You will no longer receive global %s messages.');
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index f81862717f..75720a7c28 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -603,6 +603,11 @@ void CharacterDatabaseConnection::DoPrepareStatements()
// Character names
PrepareStatement(CHAR_INS_RESERVED_PLAYER_NAME, "INSERT IGNORE INTO reserved_name (name) VALUES (?)", CONNECTION_ASYNC);
+
+ // Character settings
+ PrepareStatement(CHAR_SEL_CHAR_SETTINGS, "SELECT source, data FROM character_settings WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_REP_CHAR_SETTINGS, "REPLACE INTO character_settings (guid, source, data) VALUES (?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_CHAR_SETTINGS, "DELETE FROM character_settings WHERE guid = ?", CONNECTION_ASYNC);
}
CharacterDatabaseConnection::CharacterDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo)
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h
index 5149373fe0..ca39783c96 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.h
+++ b/src/server/database/Database/Implementation/CharacterDatabase.h
@@ -519,6 +519,10 @@ enum CharacterDatabaseStatements : uint32
CHAR_INS_RESERVED_PLAYER_NAME,
+ CHAR_SEL_CHAR_SETTINGS,
+ CHAR_REP_CHAR_SETTINGS,
+ CHAR_DEL_CHAR_SETTINGS,
+
MAX_CHARACTERDATABASE_STATEMENTS
};
diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp
index 27f84445c8..168c0497fe 100644
--- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp
@@ -984,7 +984,7 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundBracket
uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32) 80);
uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32) 80);
- sWorld->SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level, qPlayers, MaxPlayers);
+ sWorld->SendWorldTextOptional(LANG_BG_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_BG_QUEUE, bgName, q_min_level, q_max_level, qPlayers, MaxPlayers);
}
else
{
@@ -1068,7 +1068,7 @@ void BattlegroundQueue::SendMessageBGQueue(Player* leader, Battleground* bg, PvP
return;
}
- sWorld->SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level, qAlliance + qHorde, MaxPlayers);
+ sWorld->SendWorldTextOptional(LANG_BG_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_BG_QUEUE, bgName, q_min_level, q_max_level, qAlliance + qHorde, MaxPlayers);
}
}
}
@@ -1119,7 +1119,7 @@ void BattlegroundQueue::SendJoinMessageArenaQueue(Player* leader, GroupQueueInfo
return;
}
- sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD, bgName, arenatype.c_str(), q_min_level, q_max_level, qPlayers, playersNeed);
+ sWorld->SendWorldTextOptional(LANG_ARENA_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_ARENA_QUEUE, bgName, arenatype.c_str(), q_min_level, q_max_level, qPlayers, playersNeed);
}
}
else
@@ -1134,7 +1134,7 @@ void BattlegroundQueue::SendJoinMessageArenaQueue(Player* leader, GroupQueueInfo
uint32 ArenaTeamRating = ginfo->ArenaTeamRating;
std::string TeamName = team->GetName();
- sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, TeamName.c_str(), ArenaType, ArenaType, ArenaTeamRating);
+ sWorld->SendWorldTextOptional(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, ANNOUNCER_FLAG_DISABLE_ARENA_QUEUE, TeamName.c_str(), ArenaType, ArenaType, ArenaTeamRating);
}
}
@@ -1158,7 +1158,9 @@ void BattlegroundQueue::SendExitMessageArenaQueue(GroupQueueInfo* ginfo)
std::string TeamName = team->GetName();
if (ArenaType && ginfo->Players.empty())
- sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, TeamName.c_str(), ArenaType, ArenaType, ArenaTeamRating);
+ {
+ sWorld->SendWorldTextOptional(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, ANNOUNCER_FLAG_DISABLE_ARENA_QUEUE, TeamName.c_str(), ArenaType, ArenaType, ArenaTeamRating);
+ }
}
void BattlegroundQueue::SetQueueAnnouncementTimer(uint32 bracketId, int32 timer, bool isCrossFactionBG /*= true*/)
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index fb56b26102..c699ea0d8d 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -4168,6 +4168,10 @@ void Player::DeleteFromDB(ObjectGuid::LowType lowGuid, uint32 accountId, bool up
stmt->setUInt32(0, lowGuid);
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SETTINGS);
+ stmt->setUInt32(0, lowGuid);
+ trans->Append(stmt);
+
Corpse::DeleteFromDB(playerGuid, trans);
sScriptMgr->OnDeleteFromDB(trans, lowGuid);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 9469bbab06..ff2f17ab79 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -31,6 +31,7 @@
#include "ObjectMgr.h"
#include "Optional.h"
#include "PetDefines.h"
+#include "PlayerSettings.h"
#include "PlayerTaxi.h"
#include "QuestDef.h"
#include "SpellMgr.h"
@@ -875,6 +876,7 @@ enum PlayerLoginQueryIndex
PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS = 32,
PLAYER_LOGIN_QUERY_LOAD_BREW_OF_THE_MONTH = 34,
PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION = 35,
+ PLAYER_LOGIN_QUERY_LOAD_CHARACTER_SETTINGS = 36,
MAX_PLAYER_LOGIN_QUERY
};
@@ -2598,6 +2600,10 @@ public:
std::string GetPlayerName();
+ // Settings
+ [[nodiscard]] PlayerSetting GetPlayerSetting(std::string source, uint8 index);
+ void UpdatePlayerSetting(std::string source, uint8 index, uint32 value);
+
protected:
// Gamemaster whisper whitelist
WhisperListContainer WhisperList;
@@ -2680,6 +2686,7 @@ public:
void _LoadTalents(PreparedQueryResult result);
void _LoadInstanceTimeRestrictions(PreparedQueryResult result);
void _LoadBrewOfTheMonth(PreparedQueryResult result);
+ void _LoadCharacterSettings(PreparedQueryResult result);
/*********************************************************/
/*** SAVE SYSTEM ***/
@@ -2703,6 +2710,7 @@ public:
void _SaveStats(CharacterDatabaseTransaction trans);
void _SaveCharacter(bool create, CharacterDatabaseTransaction trans);
void _SaveInstanceTimeRestrictions(CharacterDatabaseTransaction trans);
+ void _SavePlayerSettings(CharacterDatabaseTransaction trans);
/*********************************************************/
/*** ENVIRONMENTAL SYSTEM ***/
@@ -2955,6 +2963,8 @@ private:
WorldLocation _corpseLocation;
Optional<float> _farSightDistance = { };
+
+ PlayerSettingMap m_charSettingsMap;
};
void AddItemsSetItem(Player* player, Item* item);
diff --git a/src/server/game/Entities/Player/PlayerSettings.cpp b/src/server/game/Entities/Player/PlayerSettings.cpp
new file mode 100644
index 0000000000..30a539ed42
--- /dev/null
+++ b/src/server/game/Entities/Player/PlayerSettings.cpp
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Tokenize.h"
+#include "StringConvert.h"
+#include "Player.h"
+
+/*********************************************************/
+/*** PLAYER SETTINGS SYSTEM ***/
+/*********************************************************/
+
+void Player::_LoadCharacterSettings(PreparedQueryResult result)
+{
+ m_charSettingsMap.clear();
+
+ if (!sWorld->getBoolConfig(CONFIG_PLAYER_SETTINGS_ENABLED))
+ {
+ return;
+ }
+
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+
+ std::string source = fields[0].GetString();;
+ std::string data = fields[1].GetString();
+
+ std::vector<std::string_view> tokens = Acore::Tokenize(data, ' ', true);
+
+ PlayerSettingVector setting;
+ setting.resize(tokens.size());
+
+ uint32 count = 0;
+
+ for (auto token : tokens)
+ {
+ PlayerSetting set;
+ set.value = Acore::StringTo<uint32>(token).value();
+ setting[++count] = set;
+ }
+
+ m_charSettingsMap[source] = setting;
+
+ } while (result->NextRow());
+ }
+}
+
+PlayerSetting Player::GetPlayerSetting(std::string source, uint8 index)
+{
+ auto itr = m_charSettingsMap.find(source);
+
+ if (itr == m_charSettingsMap.end())
+ {
+ // Settings not found, this will initialize a new entry.
+ UpdatePlayerSetting(source, index, 0);
+ return GetPlayerSetting(source, index);
+ }
+
+ return itr->second[index];
+}
+
+void Player::_SavePlayerSettings(CharacterDatabaseTransaction trans)
+{
+ if (!sWorld->getBoolConfig(CONFIG_PLAYER_SETTINGS_ENABLED))
+ {
+ return;
+ }
+
+ for (auto itr : m_charSettingsMap)
+ {
+ std::ostringstream data;
+
+ for (auto setting : itr.second)
+ {
+ data << setting.value << ' ';
+ }
+
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_SETTINGS);
+ stmt->setUInt32(0, GetGUID().GetCounter());
+ stmt->setString(1, itr.first);
+ stmt->setString(2, data.str());
+ trans->Append(stmt);
+ }
+}
+
+void Player::UpdatePlayerSetting(std::string source, uint8 index, uint32 value)
+{
+ auto itr = m_charSettingsMap.find(source);
+
+ if (itr == m_charSettingsMap.end())
+ {
+ // Settings not found, initialize a new entry.
+ uint8 size = index ? index : index + 1;
+
+ PlayerSettingVector setting;
+ setting.resize(size);
+
+ for (uint32 itr = 0; itr <= index; ++itr)
+ {
+ PlayerSetting set;
+ set.value = itr == index ? value : 0;
+
+ setting[itr] = set;
+ }
+
+ m_charSettingsMap[source] = setting;
+ }
+ else
+ {
+ itr->second[index].value = value;
+ }
+}
diff --git a/src/server/game/Entities/Player/PlayerSettings.h b/src/server/game/Entities/Player/PlayerSettings.h
new file mode 100644
index 0000000000..24d9439bd9
--- /dev/null
+++ b/src/server/game/Entities/Player/PlayerSettings.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _PLAYER_SETTINGS_H
+#define _PLAYER_SETTINGS_H
+
+class Player;
+
+const std::string AzerothcorePSSource = "ac_default";
+
+enum CharacterSettingIndexes : uint8
+{
+ SETTING_ANNOUNCER_FLAGS,
+ MAX_CHAR_SETTINGS
+};
+
+enum AnnouncerFlags : uint8
+{
+ ANNOUNCER_FLAG_DISABLE_BG_QUEUE = 1,
+ ANNOUNCER_FLAG_DISABLE_ARENA_QUEUE = 2,
+ ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST = 4
+};
+
+struct PlayerSetting
+{
+ uint32 value;
+
+ [[nodiscard]] bool HasFlag(uint32 flag) { return (value & flag) != 0; }
+ [[nodiscard]] bool IsEnabled(uint32 equals = 1) { return value == equals; }
+ void AddFlag(uint32 flag) { value = value | flag; }
+ void RemoveFlag(uint32 flag) { value = value &~ flag; }
+};
+
+typedef std::vector<PlayerSetting> PlayerSettingVector;
+typedef std::map<std::string, PlayerSettingVector> PlayerSettingMap;
+
+#endif
diff --git a/src/server/game/Entities/Player/PlayerStorage.cpp b/src/server/game/Entities/Player/PlayerStorage.cpp
index 7f64681ed3..2e62c84d8b 100644
--- a/src/server/game/Entities/Player/PlayerStorage.cpp
+++ b/src/server/game/Entities/Player/PlayerStorage.cpp
@@ -5622,6 +5622,8 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
_LoadBrewOfTheMonth(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BREW_OF_THE_MONTH));
+ _LoadCharacterSettings(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CHARACTER_SETTINGS));
+
// Players are immune to taunt
ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true);
@@ -7166,6 +7168,7 @@ void Player::SaveToDB(CharacterDatabaseTransaction trans, bool create, bool logo
GetSession()->SaveTutorialsData(trans); // changed only while character in game
_SaveGlyphs(trans);
_SaveInstanceTimeRestrictions(trans);
+ _SavePlayerSettings(trans);
// check if stats should only be saved on logout
// save stats can be out of transaction
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 297c15b4dc..65c49c9849 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -205,6 +205,10 @@ bool LoginQueryHolder::Initialize()
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION, stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_SETTINGS);
+ stmt->setUInt64(0, lowGuid);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CHARACTER_SETTINGS, stmt);
+
return res;
}
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index ea5c74cb84..1517ab0bfd 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -1244,7 +1244,11 @@ enum AcoreStrings
LANG_CMD_ITEM_REFUNDED_AP = 5077,
LANG_CMD_ITEM_REFUND_NOT_FOUND = 5078,
- // Room for more strings 5078-9999
+ LANG_CMD_AUTOBROADCAST_LVL_ERROR = 5079,
+ LANG_CMD_SETTINGS_ANNOUNCER_ON = 5080,
+ LANG_CMD_SETTINGS_ANNOUNCER_OFF = 5081,
+
+ // Room for more strings 5082-9999
// Level requirement notifications
LANG_SAY_REQ = 6604,
diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h
index 924ba75e50..ffad84b57e 100644
--- a/src/server/game/World/IWorld.h
+++ b/src/server/game/World/IWorld.h
@@ -171,6 +171,7 @@ enum WorldBoolConfigs
CONFIG_SET_BOP_ITEM_TRADEABLE,
CONFIG_ALLOW_LOGGING_IP_ADDRESSES_IN_DATABASE,
CONFIG_REALM_LOGIN_ENABLED,
+ CONFIG_PLAYER_SETTINGS_ENABLED,
BOOL_CONFIG_VALUE_COUNT
};
@@ -334,6 +335,7 @@ enum WorldIntConfigs
CONFIG_CHARDELETE_MIN_LEVEL,
CONFIG_AUTOBROADCAST_CENTER,
CONFIG_AUTOBROADCAST_INTERVAL,
+ CONFIG_AUTOBROADCAST_MIN_LEVEL_DISABLE,
CONFIG_MAX_RESULTS_LOOKUP_COMMANDS,
CONFIG_DB_PING_INTERVAL,
CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION,
@@ -537,6 +539,7 @@ public:
virtual void SetInitialWorldSettings() = 0;
virtual void LoadConfigSettings(bool reload = false) = 0;
virtual void SendWorldText(uint32 string_id, ...) = 0;
+ virtual void SendWorldTextOptional(uint32 string_id, uint32 flag, ...) = 0;
virtual void SendGlobalText(const char* text, WorldSession* self) = 0;
virtual void SendGMText(uint32 string_id, ...) = 0;
virtual void SendGlobalMessage(WorldPacket* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL) = 0;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 80a24c9519..d043903d07 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1243,6 +1243,8 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_LOOT_NEED_BEFORE_GREED_ILVL_RESTRICTION] = sConfigMgr->GetOption<int32>("LootNeedBeforeGreedILvlRestriction", 70);
+ m_bool_configs[CONFIG_PLAYER_SETTINGS_ENABLED] = sConfigMgr->GetOption<bool>("EnablePlayerSettings", 0);
+
///- Read the "Data" directory from the config file
std::string dataPath = sConfigMgr->GetOption<std::string>("DataDir", "./");
if (dataPath.empty() || (dataPath.at(dataPath.length() - 1) != '/' && dataPath.at(dataPath.length() - 1) != '\\'))
@@ -1324,6 +1326,7 @@ void World::LoadConfigSettings(bool reload)
m_bool_configs[CONFIG_AUTOBROADCAST] = sConfigMgr->GetOption<bool>("AutoBroadcast.On", false);
m_int_configs[CONFIG_AUTOBROADCAST_CENTER] = sConfigMgr->GetOption<int32>("AutoBroadcast.Center", 0);
m_int_configs[CONFIG_AUTOBROADCAST_INTERVAL] = sConfigMgr->GetOption<int32>("AutoBroadcast.Timer", 60000);
+ m_int_configs[CONFIG_AUTOBROADCAST_MIN_LEVEL_DISABLE] = sConfigMgr->GetOption<int32>("AutoBroadcast.MinDisableLevel", 0);
if (reload)
{
m_timers[WUPDATE_AUTOBROADCAST].SetInterval(m_int_configs[CONFIG_AUTOBROADCAST_INTERVAL]);
@@ -2576,6 +2579,34 @@ void World::SendWorldText(uint32 string_id, ...)
va_end(ap);
}
+void World::SendWorldTextOptional(uint32 string_id, uint32 flag, ...)
+{
+ va_list ap;
+ va_start(ap, flag);
+
+ Acore::WorldWorldTextBuilder wt_builder(string_id, &ap);
+ Acore::LocalizedPacketListDo<Acore::WorldWorldTextBuilder> wt_do(wt_builder);
+ for (auto const& itr : m_sessions)
+ {
+ if (!itr.second || !itr.second->GetPlayer() || !itr.second->GetPlayer()->IsInWorld())
+ {
+ continue;
+ }
+
+ if (sWorld->getBoolConfig(CONFIG_PLAYER_SETTINGS_ENABLED))
+ {
+ if (itr.second->GetPlayer()->GetPlayerSetting(AzerothcorePSSource, SETTING_ANNOUNCER_FLAGS).HasFlag(flag))
+ {
+ continue;
+ }
+ }
+
+ wt_do(itr.second->GetPlayer());
+ }
+
+ va_end(ap);
+}
+
/// Send a System Message to all GMs (except self if mentioned)
void World::SendGMText(uint32 string_id, ...)
{
@@ -2953,7 +2984,9 @@ void World::SendAutoBroadcast()
uint32 abcenter = sWorld->getIntConfig(CONFIG_AUTOBROADCAST_CENTER);
if (abcenter == 0)
- sWorld->SendWorldText(LANG_AUTO_BROADCAST, msg.c_str());
+ {
+ sWorld->SendWorldTextOptional(LANG_AUTO_BROADCAST, ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST, msg.c_str());
+ }
else if (abcenter == 1)
{
@@ -2964,7 +2997,7 @@ void World::SendAutoBroadcast()
else if (abcenter == 2)
{
- sWorld->SendWorldText(LANG_AUTO_BROADCAST, msg.c_str());
+ sWorld->SendWorldTextOptional(LANG_AUTO_BROADCAST, ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST, msg.c_str());
WorldPacket data(SMSG_NOTIFICATION, (msg.size() + 1));
data << msg;
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index b2f2658654..6c5713c254 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -262,6 +262,8 @@ public:
void SendZoneText(uint32 zone, const char* text, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL);
void SendServerMessage(ServerMessageType type, const char* text = "", Player* player = nullptr);
+ void SendWorldTextOptional(uint32 string_id, uint32 flag, ...);
+
/// Are we in the middle of a shutdown?
bool IsShuttingDown() const { return m_ShutdownTimer > 0; }
uint32 GetShutDownTimeLeft() const { return m_ShutdownTimer; }
diff --git a/src/server/scripts/Commands/cs_player_settings.cpp b/src/server/scripts/Commands/cs_player_settings.cpp
new file mode 100644
index 0000000000..2b7381e4fd
--- /dev/null
+++ b/src/server/scripts/Commands/cs_player_settings.cpp
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Chat.h"
+#include "Player.h"
+#include "PlayerSettings.h"
+#include "ScriptMgr.h"
+
+using namespace Acore::ChatCommands;
+
+class player_settings_commandscript : public CommandScript
+{
+public:
+ player_settings_commandscript() : CommandScript("player_settings_commandscript") {}
+
+ ChatCommandTable GetCommands() const override
+ {
+ static ChatCommandTable playerSettingsCommandTable =
+ {
+ { "announcer", HandleSettingsAnnouncerFlags, SEC_MODERATOR, Console::No },
+ };
+ static ChatCommandTable commandTable =
+ {
+ { "settings", playerSettingsCommandTable },
+ };
+ return commandTable;
+ }
+
+ static bool HandleSettingsAnnouncerFlags(ChatHandler* handler, std::string type, bool on)
+ {
+ Player* player = handler->GetPlayer();
+
+ PlayerSetting setting;
+ setting = player->GetPlayerSetting(AzerothcorePSSource, SETTING_ANNOUNCER_FLAGS);
+
+ if (type == "bg")
+ {
+ on ? setting.RemoveFlag(ANNOUNCER_FLAG_DISABLE_BG_QUEUE) : setting.AddFlag(ANNOUNCER_FLAG_DISABLE_BG_QUEUE);
+ player->UpdatePlayerSetting(AzerothcorePSSource, SETTING_ANNOUNCER_FLAGS, setting.value);
+ }
+ else if (type == "arena")
+ {
+ on ? setting.RemoveFlag(ANNOUNCER_FLAG_DISABLE_ARENA_QUEUE) : setting.AddFlag(ANNOUNCER_FLAG_DISABLE_ARENA_QUEUE);
+ player->UpdatePlayerSetting(AzerothcorePSSource, SETTING_ANNOUNCER_FLAGS, setting.value);
+ }
+ else if (type == "autobroadcast")
+ {
+ if (player->getLevel() < sWorld->getIntConfig(CONFIG_AUTOBROADCAST_MIN_LEVEL_DISABLE))
+ {
+ handler->SetSentErrorMessage(true);
+ handler->PSendSysMessage(LANG_CMD_AUTOBROADCAST_LVL_ERROR, sWorld->getIntConfig(CONFIG_AUTOBROADCAST_MIN_LEVEL_DISABLE));
+ }
+
+ on ? setting.RemoveFlag(ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST) : setting.AddFlag(ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST);
+ player->UpdatePlayerSetting(AzerothcorePSSource, SETTING_ANNOUNCER_FLAGS, setting.value);
+ }
+
+ handler->SetSentErrorMessage(false);
+ handler->PSendSysMessage(on ? LANG_CMD_SETTINGS_ANNOUNCER_ON : LANG_CMD_SETTINGS_ANNOUNCER_OFF, type);
+ return true;
+ }
+};
+
+void AddSC_player_settings_commandscript()
+{
+ new player_settings_commandscript();
+}
diff --git a/src/server/scripts/Commands/cs_script_loader.cpp b/src/server/scripts/Commands/cs_script_loader.cpp
index 1d40846ef5..4c7433b6b1 100644
--- a/src/server/scripts/Commands/cs_script_loader.cpp
+++ b/src/server/scripts/Commands/cs_script_loader.cpp
@@ -61,6 +61,7 @@ void AddSC_titles_commandscript();
void AddSC_wp_commandscript();
void AddSC_cache_commandscript();
void AddSC_item_commandscript();
+void AddSC_player_settings_commandscript();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
@@ -111,4 +112,5 @@ void AddCommandsScripts()
AddSC_wp_commandscript();
AddSC_cache_commandscript();
AddSC_item_commandscript();
+ AddSC_player_settings_commandscript();
}
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 6766a477bf..1e7fe0b39f 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -2545,6 +2545,13 @@ AutoBroadcast.Center = 0
AutoBroadcast.Timer = 60000
#
+# AutoBroadcast.MinDisableLevel
+# Description: Minimum level required to disable autobroadcast announcements if EnablePlayerSettings option is enabled.
+# Default: 0 - (Not allowed to disable it)
+
+AutoBroadcast.MinDisableLevel = 0
+
+#
###################################################################################################
###################################################################################################
@@ -3600,6 +3607,14 @@ LFG.MaxKickCount = 2
LFG.KickPreventionTimer = 900
#
+# EnablePlayerSettings
+# Description: Enables the usage of character specific settings.
+# Default: 0 - Disabled
+# 1 - Enabled
+
+EnablePlayerSettings = 0
+
+#
###################################################################################################
###################################################################################################
diff --git a/src/test/mocks/WorldMock.h b/src/test/mocks/WorldMock.h
index 6d85da9191..82a024a867 100644
--- a/src/test/mocks/WorldMock.h
+++ b/src/test/mocks/WorldMock.h
@@ -77,6 +77,7 @@ public:
MOCK_METHOD(void, SetInitialWorldSettings, ());
MOCK_METHOD(void, LoadConfigSettings, (bool reload), ());
void SendWorldText(uint32 string_id, ...) override {}
+ void SendWorldTextOptional(uint32 string_id, uint32 flag, ...) override {}
MOCK_METHOD(void, SendGlobalText, (const char* text, WorldSession* self), ());
void SendGMText(uint32 string_id, ...) override {}
MOCK_METHOD(void, SendGlobalMessage, (WorldPacket* packet, WorldSession* self, TeamId teamId), ());