From 392f6f5e44f9459478f0153db4225782c412c43d Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Wed, 11 Mar 2026 22:02:30 -0300 Subject: [PATCH] fix(Core/Battlefield): Erase invite by real team on war accept and add queue list command (#25056) Co-authored-by: Claude Sonnet 4.5 --- .../2026_03_10_00_bf_queue_command.sql | 76 +++++++++++++++++++ src/server/game/Battlefield/Battlefield.cpp | 2 +- src/server/game/Battlefield/Battlefield.h | 8 ++ src/server/game/Miscellaneous/Language.h | 10 ++- src/server/scripts/Commands/cs_bf.cpp | 63 ++++++++++++++- 5 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 data/sql/updates/pending_db_world/2026_03_10_00_bf_queue_command.sql diff --git a/data/sql/updates/pending_db_world/2026_03_10_00_bf_queue_command.sql b/data/sql/updates/pending_db_world/2026_03_10_00_bf_queue_command.sql new file mode 100644 index 000000000..911bd3193 --- /dev/null +++ b/data/sql/updates/pending_db_world/2026_03_10_00_bf_queue_command.sql @@ -0,0 +1,76 @@ +-- .bf queue command and display strings +-- Syntax: .bf queue #battleid +-- Displays players in queue, invited, and actively in war for a given battlefield. +-- +-- Output: 2 team headers + one line per player: +-- 1. Header (5120 or 5121) — args: battleId, timerSecs +-- 2. Team hdr (5122) x2 — args: teamName, queueCount, invitedCount, warCount +-- 3. Per-player (5123-5125) — queue: name | invited: name, secsLeft | war: name + +-- ---------------------------------------------------------------- +-- command table +-- ---------------------------------------------------------------- +DELETE FROM `command` WHERE `name` = 'bf queue'; +INSERT INTO `command` (`name`, `security`, `help`) VALUES +('bf queue', 2, 'Syntax: .bf queue #battleid\r\nDisplays all players currently in queue, invited, or actively in war for the specified battlefield.\r\n#battleid: the battle ID (e.g. 1 for Wintergrasp).'); + +-- ---------------------------------------------------------------- +-- acore_string (entries 5120–5125) +-- ---------------------------------------------------------------- +DELETE FROM `acore_string` WHERE `entry` BETWEEN 5120 AND 5125; +INSERT INTO `acore_string` + (`entry`, `content_default`, + `locale_koKR`, `locale_frFR`, `locale_deDE`, + `locale_zhCN`, `locale_zhTW`, + `locale_esES`, `locale_esMX`, `locale_ruRU`) +VALUES +-- 5120 : header – war in progress args: battleId, timerSecs +(5120, + 'Battlefield [{}] | WAR IN PROGRESS | Timer: {}s', + '전장 [{}] | 전투 진행 중 | 타이머: {}초', + 'Champ de bataille [{}] | GUERRE EN COURS | Minuterie : {}s', + 'Schlachtfeld [{}] | KRIEG LÄUFT | Timer: {}s', + '战场 [{}] | 战斗进行中 | 计时器: {}秒', + '戰場 [{}] | 戰鬥進行中 | 計時器: {}秒', + 'Campo de batalla [{}] | GUERRA EN CURSO | Temporizador: {}s', + 'Campo de batalla [{}] | GUERRA EN CURSO | Temporizador: {}s', + 'Поле боя [{}] | ВОЙНА ИДЁТ | Таймер: {}с'), + +-- 5121 : header – waiting for battle args: battleId, timerSecs +(5121, + 'Battlefield [{}] | Waiting for battle | Timer: {}s', + '전장 [{}] | 전투 대기 중 | 타이머: {}초', + 'Champ de bataille [{}] | En attente de bataille | Minuterie : {}s', + 'Schlachtfeld [{}] | Warten auf die Schlacht | Timer: {}s', + '战场 [{}] | 等待战斗 | 计时器: {}秒', + '戰場 [{}] | 等待戰鬥 | 計時器: {}秒', + 'Campo de batalla [{}] | Esperando la batalla | Temporizador: {}s', + 'Campo de batalla [{}] | Esperando la batalla | Temporizador: {}s', + 'Поле боя [{}] | Ожидание битвы | Таймер: {}с'), + +-- 5122 : team header args: teamName, queueCount, invitedCount, warCount +(5122, + '=== {} | Queue: {} | Invited: {} | War: {} ===', + '=== {} | 대기열: {} | 초대됨: {} | 전투 중: {} ===', + '=== {} | File : {} | Invités : {} | En guerre : {} ===', + '=== {} | Warteschlange: {} | Eingeladen: {} | Im Krieg: {} ===', + '=== {} | 队列: {} | 已邀请: {} | 战斗中: {} ===', + '=== {} | 佇列: {} | 已邀請: {} | 戰鬥中: {} ===', + '=== {} | Cola: {} | Invitados: {} | En guerra: {} ===', + '=== {} | Cola: {} | Invitados: {} | En guerra: {} ===', + '=== {} | Очередь: {} | Приглашённые: {} | В бою: {} ==='), + +-- 5123 : player in queue args: playerName +(5123, + ' [Q] {}', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + +-- 5124 : player invited args: playerName, secsLeft +(5124, + ' [I] {} ({}s)', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + +-- 5125 : player in war args: playerName +(5125, + ' [W] {}', + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index ace179e8f..63f72c3aa 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -442,7 +442,7 @@ void Battlefield::PlayerAcceptInviteToWar(Player* player) { player->GetSession()->SendBfEntered(m_BattleId); m_PlayersInWar[player->GetTeamId()].insert(player->GetGUID()); - m_InvitedPlayers[player->GetTeamId()].erase(player->GetGUID()); + m_InvitedPlayers[player->GetTeamId(true)].erase(player->GetGUID()); if (player->isAFK()) player->ToggleAFK(); diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index 0e767a441..b8f853266 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -361,6 +361,14 @@ public: // Returns the maximum players allowed per team uint32 GetMaxPlayersPerTeam() const { return m_MaxPlayer; } + /// Returns the set of players waiting in the pre-battle queue (per team, read-only). + GuidUnorderedSet const& GetPlayersQueueSet(TeamId teamId) const { return m_PlayersInQueue[teamId]; } + /// Returns the map of players invited to join the active war, value is invite expiry + /// timestamp (per team, read-only). + PlayerTimerMap const& GetInvitedPlayersMap(TeamId teamId) const { return m_InvitedPlayers[teamId]; } + /// Returns the set of players actively fighting in the war (per team, read-only). + GuidUnorderedSet const& GetPlayersInWarSet(TeamId teamId) const { return m_PlayersInWar[teamId]; } + void DoPlaySoundToAll(uint32 SoundID); void InvitePlayerToQueue(Player* player); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 7ba4c975a..70ff2a0ff 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1194,7 +1194,15 @@ enum AcoreStrings LANG_RESETALL_HONOR = 5118, LANG_RESETALL_ARENA = 5119, - // Room for more strings 5120-9999 + + // Battlefield queue display (.bf queue) + LANG_BF_QUEUE_HDR_WAR = 5120, + LANG_BF_QUEUE_HDR_WAIT = 5121, + LANG_BF_QUEUE_TEAM_HDR = 5122, + LANG_BF_QUEUE_PLAYER_QUEUE = 5123, + LANG_BF_QUEUE_PLAYER_INVITED = 5124, + LANG_BF_QUEUE_PLAYER_WAR = 5125, + // Room for more strings 5126-9999 // Level requirement notifications LANG_SAY_REQ = 6604, diff --git a/src/server/scripts/Commands/cs_bf.cpp b/src/server/scripts/Commands/cs_bf.cpp index 4224068b9..815f1fb20 100644 --- a/src/server/scripts/Commands/cs_bf.cpp +++ b/src/server/scripts/Commands/cs_bf.cpp @@ -19,6 +19,9 @@ #include "Chat.h" #include "CommandScript.h" #include "Language.h" +#include "GameTime.h" +#include "ObjectAccessor.h" +#include "Player.h" using namespace Acore::ChatCommands; @@ -35,7 +38,8 @@ public: { "stop", HandleBattlefieldEnd, SEC_ADMINISTRATOR, Console::Yes }, { "switch", HandleBattlefieldSwitch, SEC_ADMINISTRATOR, Console::Yes }, { "timer", HandleBattlefieldTimer, SEC_ADMINISTRATOR, Console::Yes }, - { "enable", HandleBattlefieldEnable, SEC_ADMINISTRATOR, Console::Yes } + { "enable", HandleBattlefieldEnable, SEC_ADMINISTRATOR, Console::Yes }, + { "queue", HandleBattlefieldQueue, SEC_GAMEMASTER, Console::Yes } }; static ChatCommandTable commandTable = { @@ -167,6 +171,63 @@ public: return true; } + + static bool HandleBattlefieldQueue(ChatHandler* handler, uint32 battleId) + { + Battlefield* bf = sBattlefieldMgr->GetBattlefieldByBattleId(battleId); + + if (!bf) + { + handler->SendErrorMessage(LANG_BF_NOT_FOUND, battleId); + return false; + } + + handler->PSendSysMessage(bf->IsWarTime() ? LANG_BF_QUEUE_HDR_WAR : LANG_BF_QUEUE_HDR_WAIT, + battleId, bf->GetTimer() / IN_MILLISECONDS); + + static char const* teamNames[PVP_TEAMS_COUNT] = { "Alliance", "Horde" }; + + std::string offlineSuffix = handler->GetAcoreString(LANG_OFFLINE); + + auto nameOf = [offlineSuffix](ObjectGuid guid) -> std::string + { + if (Player* p = ObjectAccessor::FindPlayer(guid)) + return p->GetName(); + return std::to_string(guid.GetCounter()) + offlineSuffix; + }; + + for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i) + { + TeamId team = TeamId(i); + + GuidUnorderedSet const& inQueue = bf->GetPlayersQueueSet(team); + PlayerTimerMap const& invited = bf->GetInvitedPlayersMap(team); + GuidUnorderedSet const& inWar = bf->GetPlayersInWarSet(team); + + handler->PSendSysMessage(LANG_BF_QUEUE_TEAM_HDR, + teamNames[i], + static_cast(inQueue.size()), + static_cast(invited.size()), + static_cast(inWar.size())); + + for (ObjectGuid const& guid : inQueue) + handler->PSendSysMessage(LANG_BF_QUEUE_PLAYER_QUEUE, nameOf(guid)); + + SystemTimePoint now = GameTime::GetSystemTime(); + for (auto const& [guid, expiry] : invited) + { + SystemTimePoint expiryPoint = std::chrono::system_clock::from_time_t(expiry); + int32 secsLeft = std::max(int32(0), static_cast( + std::chrono::duration_cast(expiryPoint - now).count())); + handler->PSendSysMessage(LANG_BF_QUEUE_PLAYER_INVITED, nameOf(guid), secsLeft); + } + + for (ObjectGuid const& guid : inWar) + handler->PSendSysMessage(LANG_BF_QUEUE_PLAYER_WAR, nameOf(guid)); + } + + return true; + } }; void AddSC_bf_commandscript()