diff --git a/data/sql/updates/pending_db_world/rev_1774073616034639439.sql b/data/sql/updates/pending_db_world/rev_1774073616034639439.sql
new file mode 100644
index 000000000..4a51df829
--- /dev/null
+++ b/data/sql/updates/pending_db_world/rev_1774073616034639439.sql
@@ -0,0 +1,21 @@
+-- Add autobroadcast commands
+DELETE FROM `command` WHERE `name` IN ('autobroadcast', 'autobroadcast list', 'autobroadcast add', 'autobroadcast locale', 'autobroadcast remove');
+INSERT INTO `command` (`name`, `security`, `help`) VALUES
+('autobroadcast', 2, 'Syntax: .autobroadcast $subcommand\nType .autobroadcast to see a list of subcommands or .help autobroadcast $subcommand to see info on subcommands.'),
+('autobroadcast list', 2, 'Syntax: .autobroadcast list\nList all autobroadcast entries.'),
+('autobroadcast add', 3, 'Syntax: .autobroadcast add $weight $text\nAdd a new autobroadcast entry with the given weight and text.'),
+('autobroadcast locale', 3, 'Syntax: .autobroadcast locale $id $locale $text\nAdd or replace a localized text for the autobroadcast entry with the given ID.'),
+('autobroadcast remove', 3, 'Syntax: .autobroadcast remove $id\nRemove the autobroadcast entry with the given ID and its locale entries.');
+
+-- Add acore_string entries for autobroadcast commands
+DELETE FROM `acore_string` WHERE `entry` IN (5126, 5127, 5128, 5129, 5130, 5131, 5132, 5133, 5134);
+INSERT INTO `acore_string` (`entry`, `content_default`, `locale_koKR`, `locale_frFR`, `locale_deDE`, `locale_zhCN`, `locale_zhTW`, `locale_esES`, `locale_esMX`, `locale_ruRU`) VALUES
+(5126, 'Autobroadcast entries:', '자동 방송 항목:', 'Entrées d''annonce automatique :', 'Autobroadcast-Einträge:', '自动广播条目:', '自動廣播條目:', 'Entradas de transmisión automática:', 'Entradas de transmisión automática:', 'Записи автоматической рассылки:'),
+(5127, ' ID: {} | Weight: {} | Text: {}', ' ID: {} | 가중치: {} | 텍스트: {}', ' ID : {} | Poids : {} | Texte : {}', ' ID: {} | Gewicht: {} | Text: {}', ' ID:{} | 权重:{} | 文本:{}', ' ID:{} | 權重:{} | 文本:{}', ' ID: {} | Peso: {} | Texto: {}', ' ID: {} | Peso: {} | Texto: {}', ' ID: {} | Вес: {} | Текст: {}'),
+(5128, 'No autobroadcast entries found.', '자동 방송 항목을 찾을 수 없습니다.', 'Aucune entrée d''annonce automatique trouvée.', 'Keine Autobroadcast-Einträge gefunden.', '未找到自动广播条目。', '未找到自動廣播條目。', 'No se encontraron entradas de transmisión automática.', 'No se encontraron entradas de transmisión automática.', 'Записи автоматической рассылки не найдены.'),
+(5129, 'Autobroadcast entry added with ID {}.', 'ID {}로 자동 방송 항목이 추가되었습니다.', 'Entrée d''annonce automatique ajoutée avec l''ID {}.', 'Autobroadcast-Eintrag mit ID {} hinzugefügt.', '已添加ID为{}的自动广播条目。', '已新增ID為{}的自動廣播條目。', 'Entrada de transmisión automática añadida con ID {}.', 'Entrada de transmisión automática añadida con ID {}.', 'Добавлена запись автоматической рассылки с ID {}.'),
+(5130, 'Autobroadcast entry #{} removed.', '자동 방송 항목 #{}이(가) 제거되었습니다.', 'Entrée d''annonce automatique #{} supprimée.', 'Autobroadcast-Eintrag #{} entfernt.', '自动广播条目 #{} 已移除。', '自動廣播條目 #{} 已移除。', 'Entrada de transmisión automática #{} eliminada.', 'Entrada de transmisión automática #{} eliminada.', 'Запись автоматической рассылки #{} удалена.'),
+(5131, 'Autobroadcast entry #{} not found.', '자동 방송 항목 #{}을(를) 찾을 수 없습니다.', 'Entrée d''annonce automatique #{} introuvable.', 'Autobroadcast-Eintrag #{} nicht gefunden.', '未找到自动广播条目 #{}。', '未找到自動廣播條目 #{}。', 'Entrada de transmisión automática #{} no encontrada.', 'Entrada de transmisión automática #{} no encontrada.', 'Запись автоматической рассылки #{} не найдена.'),
+(5132, 'Autobroadcast locale ''{}'' added for entry #{}.', '자동 방송 항목 #{}에 로캘 ''{}''이(가) 추가되었습니다.', 'Localisation ''{}'' ajoutée pour l''entrée d''annonce automatique #{}.', 'Autobroadcast-Lokalisierung ''{}'' für Eintrag #{} hinzugefügt.', '已为自动广播条目 #{} 添加语言区域 ''{}''。', '已為自動廣播條目 #{} 新增語言區域 ''{}''。', 'Localización ''{}'' añadida para la entrada de transmisión automática #{}.', 'Localización ''{}'' añadida para la entrada de transmisión automática #{}.', 'Локализация ''{}'' добавлена для записи автоматической рассылки #{}.'),
+(5133, ' Locale: {} | Text: {}', ' 로캘: {} | 텍스트: {}', ' Langue : {} | Texte : {}', ' Sprache: {} | Text: {}', ' 语言区域:{} | 文本:{}', ' 語言區域:{} | 文本:{}', ' Localización: {} | Texto: {}', ' Localización: {} | Texto: {}', ' Локализация: {} | Текст: {}'),
+(5134, 'Invalid locale. Valid locales: enUS, koKR, frFR, deDE, zhCN, zhTW, esES, esMX, ruRU.', '잘못된 로캘입니다. 유효한 로캘: enUS, koKR, frFR, deDE, zhCN, zhTW, esES, esMX, ruRU.', 'Langue invalide. Langues valides : enUS, koKR, frFR, deDE, zhCN, zhTW, esES, esMX, ruRU.', 'Ungültige Sprache. Gültige Sprachen: enUS, koKR, frFR, deDE, zhCN, zhTW, esES, esMX, ruRU.', '无效的语言区域。有效的语言区域:enUS、koKR、frFR、deDE、zhCN、zhTW、esES、esMX、ruRU。', '無效的語言區域。有效的語言區域:enUS、koKR、frFR、deDE、zhCN、zhTW、esES、esMX、ruRU。', 'Localización inválida. Localizaciones válidas: enUS, koKR, frFR, deDE, zhCN, zhTW, esES, esMX, ruRU.', 'Localización inválida. Localizaciones válidas: enUS, koKR, frFR, deDE, zhCN, zhTW, esES, esMX, ruRU.', 'Недопустимая локализация. Допустимые локализации: enUS, koKR, frFR, deDE, zhCN, zhTW, esES, esMX, ruRU.');
diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp
index 298ae09d5..256664672 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/database/Database/Implementation/LoginDatabase.cpp
@@ -118,6 +118,13 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_AUTOBROADCAST, "SELECT id, weight, text FROM autobroadcast WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_AUTOBROADCAST_LOCALIZED, "SELECT id, locale, text FROM autobroadcast_locale WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_INS_AUTOBROADCAST, "INSERT INTO autobroadcast (realmid, weight, text) VALUES (?, ?, ?)", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_DEL_AUTOBROADCAST, "DELETE FROM autobroadcast WHERE id = ? AND (realmid = ? OR realmid = -1)", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_INS_AUTOBROADCAST_LOCALE, "REPLACE INTO autobroadcast_locale (realmid, id, locale, text) VALUES (?, ?, ?, ?)", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_DEL_AUTOBROADCAST_LOCALE, "DELETE FROM autobroadcast_locale WHERE id = ? AND (realmid = ? OR realmid = -1)", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_AUTOBROADCAST_BY_ID, "SELECT 1 FROM autobroadcast WHERE id = ? AND (realmid = ? OR realmid = -1)", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_AUTOBROADCAST_LOCALE_BY_ID, "SELECT locale, text FROM autobroadcast_locale WHERE (realmid = ? OR realmid = -1) AND id = ?", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_AUTOBROADCAST_MAX_ID, "SELECT MAX(id) FROM autobroadcast WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_MOTD, "SELECT text FROM motd WHERE realmid = ? OR realmid = -1 ORDER BY realmid DESC", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_MOTD_LOCALE, "SELECT locale, text FROM motd_localized WHERE realmid = ? OR realmid = -1 ORDER BY realmid DESC", CONNECTION_SYNCH);
PrepareStatement(LOGIN_REP_MOTD, "REPLACE INTO motd (realmid, text) VALUES (?, ?)", CONNECTION_ASYNC);
diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h
index 563cdf3eb..6b6debb81 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.h
+++ b/src/server/database/Database/Implementation/LoginDatabase.h
@@ -100,6 +100,13 @@ enum LoginDatabaseStatements : uint32
LOGIN_DEL_ACCOUNT,
LOGIN_SEL_AUTOBROADCAST,
LOGIN_SEL_AUTOBROADCAST_LOCALIZED,
+ LOGIN_INS_AUTOBROADCAST,
+ LOGIN_DEL_AUTOBROADCAST,
+ LOGIN_INS_AUTOBROADCAST_LOCALE,
+ LOGIN_DEL_AUTOBROADCAST_LOCALE,
+ LOGIN_SEL_AUTOBROADCAST_BY_ID,
+ LOGIN_SEL_AUTOBROADCAST_LOCALE_BY_ID,
+ LOGIN_SEL_AUTOBROADCAST_MAX_ID,
LOGIN_SEL_MOTD,
LOGIN_SEL_MOTD_LOCALE,
LOGIN_REP_MOTD,
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 61977af9e..23847a5f3 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -1203,7 +1203,19 @@ enum AcoreStrings
LANG_BF_QUEUE_PLAYER_QUEUE = 5123,
LANG_BF_QUEUE_PLAYER_INVITED = 5124,
LANG_BF_QUEUE_PLAYER_WAR = 5125,
- // Room for more strings 5126-9999
+
+ // Autobroadcast commands
+ LANG_AUTOBROADCAST_LIST_HEADER = 5126,
+ LANG_AUTOBROADCAST_LIST_ENTRY = 5127,
+ LANG_AUTOBROADCAST_LIST_EMPTY = 5128,
+ LANG_AUTOBROADCAST_ADD_SUCCESS = 5129,
+ LANG_AUTOBROADCAST_REMOVE_SUCCESS = 5130,
+ LANG_AUTOBROADCAST_NOT_FOUND = 5131,
+ LANG_AUTOBROADCAST_LOCALE_SUCCESS = 5132,
+ LANG_AUTOBROADCAST_LOCALE_ENTRY = 5133,
+ LANG_AUTOBROADCAST_INVALID_LOCALE = 5134,
+
+ // Room for more strings 5135-9999
// Level requirement notifications
LANG_SAY_REQ = 6604,
diff --git a/src/server/scripts/Commands/cs_autobroadcast.cpp b/src/server/scripts/Commands/cs_autobroadcast.cpp
new file mode 100644
index 000000000..27b5a8c20
--- /dev/null
+++ b/src/server/scripts/Commands/cs_autobroadcast.cpp
@@ -0,0 +1,208 @@
+/*
+ * 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 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 .
+ */
+
+#include "AutobroadcastMgr.h"
+#include "Chat.h"
+#include "CommandScript.h"
+#include "Config.h"
+#include "Language.h"
+
+using namespace Acore::ChatCommands;
+
+class autobroadcast_commandscript : public CommandScript
+{
+public:
+ autobroadcast_commandscript() : CommandScript("autobroadcast_commandscript") { }
+
+ ChatCommandTable GetCommands() const override
+ {
+ static ChatCommandTable autobroadcastCommandTable =
+ {
+ { "list", HandleAutobroadcastListCommand, SEC_GAMEMASTER, Console::Yes },
+ { "add", HandleAutobroadcastAddCommand, SEC_ADMINISTRATOR, Console::Yes },
+ { "locale", HandleAutobroadcastLocaleCommand, SEC_ADMINISTRATOR, Console::Yes },
+ { "remove", HandleAutobroadcastRemoveCommand, SEC_ADMINISTRATOR, Console::Yes }
+ };
+
+ static ChatCommandTable commandTable =
+ {
+ { "autobroadcast", autobroadcastCommandTable }
+ };
+
+ return commandTable;
+ }
+
+ static bool HandleAutobroadcastListCommand(ChatHandler* handler)
+ {
+ uint32 realmId = sConfigMgr->GetOption("RealmID", 0);
+
+ LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST);
+ stmt->SetData(0, realmId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (!result)
+ {
+ handler->SendSysMessage(LANG_AUTOBROADCAST_LIST_EMPTY);
+ return true;
+ }
+
+ // Prefetch all locales and group by id
+ LoginDatabasePreparedStatement* localeStmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST_LOCALIZED);
+ localeStmt->SetData(0, realmId);
+ PreparedQueryResult localeResult = LoginDatabase.Query(localeStmt);
+
+ std::unordered_map>> localeMap;
+ if (localeResult)
+ {
+ do
+ {
+ Field* localeFields = localeResult->Fetch();
+ uint32 localeId = localeFields[0].Get();
+ std::string locale = localeFields[1].Get();
+ std::string localeText = localeFields[2].Get();
+ localeMap[localeId].emplace_back(std::move(locale), std::move(localeText));
+ } while (localeResult->NextRow());
+ }
+
+ handler->SendSysMessage(LANG_AUTOBROADCAST_LIST_HEADER);
+
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 id = fields[0].Get();
+ uint8 weight = fields[1].Get();
+ std::string text = fields[2].Get();
+
+ handler->PSendSysMessage(LANG_AUTOBROADCAST_LIST_ENTRY, id, weight, text);
+
+ auto itr = localeMap.find(id);
+ if (itr != localeMap.end())
+ for (auto const& [locale, localeText] : itr->second)
+ handler->PSendSysMessage(LANG_AUTOBROADCAST_LOCALE_ENTRY, locale, localeText);
+ } while (result->NextRow());
+
+ return true;
+ }
+
+ static bool HandleAutobroadcastAddCommand(ChatHandler* handler, uint8 weight, Tail text)
+ {
+ if (text.empty())
+ return false;
+
+ uint32 realmId = sConfigMgr->GetOption("RealmID", 0);
+
+ LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_AUTOBROADCAST);
+ stmt->SetData(0, realmId);
+ stmt->SetData(1, weight);
+ stmt->SetData(2, std::string(text));
+ LoginDatabase.DirectExecute(stmt);
+
+ // Retrieve the newly inserted ID
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST_MAX_ID);
+ stmt->SetData(0, realmId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ uint32 newId = 0;
+ if (result)
+ newId = result->Fetch()[0].Get();
+
+ sAutobroadcastMgr->LoadAutobroadcasts();
+ sAutobroadcastMgr->LoadAutobroadcastsLocalized();
+
+ handler->PSendSysMessage(LANG_AUTOBROADCAST_ADD_SUCCESS, newId);
+ return true;
+ }
+
+ static bool HandleAutobroadcastLocaleCommand(ChatHandler* handler, uint32 id, std::string locale, Tail text)
+ {
+ if (text.empty())
+ return false;
+
+ if (!IsLocaleValid(locale))
+ {
+ handler->SendErrorMessage(LANG_AUTOBROADCAST_INVALID_LOCALE);
+ return true;
+ }
+
+ uint32 realmId = sConfigMgr->GetOption("RealmID", 0);
+
+ // Verify the autobroadcast entry exists
+ LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST_BY_ID);
+ stmt->SetData(0, id);
+ stmt->SetData(1, realmId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (!result)
+ {
+ handler->SendErrorMessage(LANG_AUTOBROADCAST_NOT_FOUND, id);
+ return true;
+ }
+
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_AUTOBROADCAST_LOCALE);
+ stmt->SetData(0, realmId);
+ stmt->SetData(1, id);
+ stmt->SetData(2, locale);
+ stmt->SetData(3, std::string(text));
+ LoginDatabase.DirectExecute(stmt);
+
+ sAutobroadcastMgr->LoadAutobroadcasts();
+ sAutobroadcastMgr->LoadAutobroadcastsLocalized();
+
+ handler->PSendSysMessage(LANG_AUTOBROADCAST_LOCALE_SUCCESS, locale, id);
+ return true;
+ }
+
+ static bool HandleAutobroadcastRemoveCommand(ChatHandler* handler, uint32 id)
+ {
+ uint32 realmId = sConfigMgr->GetOption("RealmID", 0);
+
+ // Verify the autobroadcast entry exists
+ LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST_BY_ID);
+ stmt->SetData(0, id);
+ stmt->SetData(1, realmId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (!result)
+ {
+ handler->SendErrorMessage(LANG_AUTOBROADCAST_NOT_FOUND, id);
+ return true;
+ }
+
+ // Delete the autobroadcast entry
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_AUTOBROADCAST);
+ stmt->SetData(0, id);
+ stmt->SetData(1, realmId);
+ LoginDatabase.DirectExecute(stmt);
+
+ // Delete associated locale entries
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_AUTOBROADCAST_LOCALE);
+ stmt->SetData(0, id);
+ stmt->SetData(1, realmId);
+ LoginDatabase.DirectExecute(stmt);
+
+ sAutobroadcastMgr->LoadAutobroadcasts();
+ sAutobroadcastMgr->LoadAutobroadcastsLocalized();
+
+ handler->PSendSysMessage(LANG_AUTOBROADCAST_REMOVE_SUCCESS, id);
+ return true;
+ }
+};
+
+void AddSC_autobroadcast_commandscript()
+{
+ new autobroadcast_commandscript();
+}
diff --git a/src/server/scripts/Commands/cs_script_loader.cpp b/src/server/scripts/Commands/cs_script_loader.cpp
index 68bd683f7..8b867a0fa 100644
--- a/src/server/scripts/Commands/cs_script_loader.cpp
+++ b/src/server/scripts/Commands/cs_script_loader.cpp
@@ -19,6 +19,7 @@
void AddSC_account_commandscript();
void AddSC_achievement_commandscript();
void AddSC_arena_commandscript();
+void AddSC_autobroadcast_commandscript();
void AddSC_bag_commandscript();
void AddSC_ban_commandscript();
void AddSC_bf_commandscript();
@@ -73,6 +74,7 @@ void AddCommandsScripts()
AddSC_account_commandscript();
AddSC_achievement_commandscript();
AddSC_arena_commandscript();
+ AddSC_autobroadcast_commandscript();
AddSC_bag_commandscript();
AddSC_ban_commandscript();
AddSC_bf_commandscript();