Advertisement
Guest User

bg

a guest
Jan 22nd, 2019
230
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 51.34 KB | None | 0 0
  1. /*
  2.  * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
  3.  * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License as published by the
  7.  * Free Software Foundation; either version 2 of the License, or (at your
  8.  * option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful, but WITHOUT
  11.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12.  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13.  * more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License along
  16.  * with this program. If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. #include "ArenaTeam.h"
  20. #include "ArenaTeamMgr.h"
  21. #include "BattlegroundMgr.h"
  22. #include "BattlegroundQueue.h"
  23. #include "Chat.h"
  24. #include "Group.h"
  25. #include "Log.h"
  26. #include "Language.h"
  27. #include "ObjectMgr.h"
  28. #include "Player.h"
  29.  
  30. /*********************************************************/
  31. /***            BATTLEGROUND QUEUE SYSTEM              ***/
  32. /*********************************************************/
  33.  
  34. BattlegroundQueue::BattlegroundQueue()
  35. {
  36.     for (uint32 i = 0; i < BG_TEAMS_COUNT; ++i)
  37.     {
  38.         for (uint32 j = 0; j < MAX_BATTLEGROUND_BRACKETS; ++j)
  39.         {
  40.             m_SumOfWaitTimes[i][j] = 0;
  41.             m_WaitTimeLastPlayer[i][j] = 0;
  42.             for (uint32 k = 0; k < COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME; ++k)
  43.                 m_WaitTimes[i][j][k] = 0;
  44.         }
  45.     }
  46. }
  47.  
  48. BattlegroundQueue::~BattlegroundQueue()
  49. {
  50.     m_events.KillAllEvents(false);
  51.  
  52.     for (int i = 0; i < MAX_BATTLEGROUND_BRACKETS; ++i)
  53.     {
  54.         for (uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; ++j)
  55.         {
  56.            
  57.         }
  58.     }
  59. }
  60.  
  61. /*********************************************************/
  62. /***      BATTLEGROUND QUEUE SELECTION POOLS           ***/
  63. /*********************************************************/
  64.  
  65. // selection pool initialization, used to clean up from prev selection
  66. void BattlegroundQueue::SelectionPool::Init()
  67. {
  68.     SelectedGroups.clear();
  69.     PlayerCount = 0;
  70. }
  71.  
  72. // remove group info from selection pool
  73. // returns true when we need to try to add new group to selection pool
  74. // returns false when selection pool is ok or when we kicked smaller group than we need to kick
  75. // sometimes it can be called on empty selection pool
  76. bool BattlegroundQueue::SelectionPool::KickGroup(uint32 size)
  77. {
  78.     //find maxgroup or LAST group with size == size and kick it
  79.     bool found = false;
  80.     GroupsQueueType::iterator groupToKick = SelectedGroups.begin();
  81.     for (GroupsQueueType::iterator itr = groupToKick; itr != SelectedGroups.end(); ++itr)
  82.     {
  83.         if (abs((int32)((*itr)->Players.size() - size)) <= 1)
  84.         {
  85.             groupToKick = itr;
  86.             found = true;
  87.         }
  88.         else if (!found && (*itr)->Players.size() >= (*groupToKick)->Players.size())
  89.             groupToKick = itr;
  90.     }
  91.     //if pool is empty, do nothing
  92.     if (GetPlayerCount())
  93.     {
  94.         //update player count
  95.         GroupQueueInfo* ginfo = (*groupToKick);
  96.         SelectedGroups.erase(groupToKick);
  97.         PlayerCount -= ginfo->Players.size();
  98.         //return false if we kicked smaller group or there are enough players in selection pool
  99.         if (ginfo->Players.size() <= size + 1)
  100.             return false;
  101.     }
  102.     return true;
  103. }
  104.  
  105. // add group to selection pool
  106. // used when building selection pools
  107. // returns true if we can invite more players, or when we added group to selection pool
  108. // returns false when selection pool is full
  109. bool BattlegroundQueue::SelectionPool::AddGroup(GroupQueueInfo* ginfo, uint32 desiredCount)
  110. {
  111.     //if group is larger than desired count - don't allow to add it to pool
  112.     if (!ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size())
  113.     {
  114.         SelectedGroups.push_back(ginfo);
  115.         // increase selected players count
  116.         PlayerCount += ginfo->Players.size();
  117.         return true;
  118.     }
  119.     if (PlayerCount < desiredCount)
  120.         return true;
  121.     return false;
  122. }
  123.  
  124. /*********************************************************/
  125. /***               BATTLEGROUND QUEUES                 ***/
  126. /*********************************************************/
  127.  
  128. // add group or player (grp == NULL) to bg queue with the given leader and bg specifications
  129. GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, BattlegroundTypeId BgTypeId, PvPDifficultyEntry const*  bracketEntry, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 MatchmakerRating, uint32 arenateamid)
  130. {
  131.     BattlegroundBracketId bracketId = bracketEntry->GetBracketId();
  132.  
  133.     // create new ginfo
  134.     GroupQueueInfo* ginfo            = new GroupQueueInfo;
  135.     ginfo->BgTypeId                  = BgTypeId;
  136.     ginfo->ArenaType                 = ArenaType;
  137.     ginfo->ArenaTeamId               = arenateamid;
  138.     ginfo->IsRated                   = isRated;
  139.     ginfo->IsInvitedToBGInstanceGUID = 0;
  140.     ginfo->JoinTime                  = getMSTime();
  141.     ginfo->RemoveInviteTime          = 0;
  142.     ginfo->Team                      = leader->GetTeam();
  143.     ginfo->ArenaTeamRating           = ArenaRating;
  144.     ginfo->ArenaMatchmakerRating     = MatchmakerRating;
  145.     ginfo->OpponentsTeamRating       = 0;
  146.     ginfo->OpponentsMatchmakerRating = 0;
  147.  
  148.     ginfo->Players.clear();
  149.  
  150.     //compute index (if group is premade or joined a rated match) to queues
  151.     uint32 index = 0;
  152.     if (!isRated && !isPremade)
  153.         index += BG_TEAMS_COUNT;
  154.     if (ginfo->Team == HORDE)
  155.         index++;
  156.  
  157.     if (sWorld->getBoolConfig(BATTLEGROUND_CROSSFACTION_ENABLED) && ArenaType == 0)
  158.         index = BG_QUEUE_MIXED;                      // BG_QUEUE_*_* -> BG_QUEUE_MIXED
  159.  
  160.  
  161.     TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "Adding Group to BattlegroundQueue bgTypeId : %u, bracket_id : %u, index : %u", BgTypeId, bracketId, index);
  162.  
  163.     uint32 lastOnlineTime = getMSTime();
  164.  
  165.     //announce world (this don't need mutex)
  166.     if (isRated && sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE))
  167.     {
  168.         ArenaTeam* Team = sArenaTeamMgr->GetArenaTeamById(arenateamid);
  169.         if (Team)
  170.             sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, Team->GetName().c_str(), ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
  171.     }
  172.  
  173.     //add players from group to ginfo
  174.     if (grp)
  175.     {
  176.         for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
  177.         {
  178.             Player* member = itr->GetSource();
  179.             if (!member)
  180.                 continue;   // this should never happen
  181.             PlayerQueueInfo& pl_info = m_QueuedPlayers[member->GetGUID()];
  182.             pl_info.LastOnlineTime   = lastOnlineTime;
  183.             pl_info.GroupInfo        = ginfo;
  184.             // add the pinfo to ginfo's list
  185.             ginfo->Players[member->GetGUID()]  = &pl_info;
  186.         }
  187.     }
  188.     else
  189.     {
  190.         PlayerQueueInfo& pl_info = m_QueuedPlayers[leader->GetGUID()];
  191.         pl_info.LastOnlineTime   = lastOnlineTime;
  192.         pl_info.GroupInfo        = ginfo;
  193.         ginfo->Players[leader->GetGUID()]  = &pl_info;
  194.     }
  195.  
  196.     //add GroupInfo to m_QueuedGroups
  197.     {
  198.         //ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock);
  199.         m_QueuedGroups[bracketId][index].push_back(ginfo);
  200.  
  201.         //announce to world, this code needs mutex
  202.         if (!isRated && !isPremade && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
  203.         {
  204.             if (Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(ginfo->BgTypeId))
  205.             {
  206.                 if (sWorld->getBoolConfig(BATTLEGROUND_CROSSFACTION_ENABLED))
  207.                 {
  208.                     char const* bgName = bg->GetName();
  209.                     uint32 MinPlayers = bg->GetMinPlayersPerTeam() * 2;
  210.                     uint32 qPlayers = 0;
  211.                     uint32 q_min_level = bracketEntry->minLevel;
  212.                     uint32 q_max_level = bracketEntry->maxLevel;
  213.                    
  214.                     for (GroupsQueueType::const_iterator itr = m_QueuedGroups[bracketId][BG_QUEUE_MIXED].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_MIXED].end(); ++itr)
  215.                         if (!(*itr)->IsInvitedToBGInstanceGUID)
  216.                             qPlayers += (*itr)->Players.size();
  217.  
  218.                     if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
  219.                     {
  220.                         ChatHandler(leader->GetSession()).PSendSysMessage("Queue status for %s (Lvl: %u to %u) Queued players: %u (Need at least %u more)", bgName, q_min_level, q_max_level, qPlayers, MinPlayers - qPlayers);
  221.                     }
  222.                     else
  223.                     {
  224.                         std::ostringstream ss;
  225.                         ss << "|cffff0000[BG Queue Announcer]:|r " << bgName << " -- [" << q_min_level << "-" << q_max_level << "] " << qPlayers << "/" << MinPlayers;
  226.                         sWorld->SendGlobalText(ss.str().c_str(), NULL);
  227.                     }
  228.                 }
  229.                 else
  230.                 {
  231.                     char const* bgName = bg->GetName();
  232.                     uint32 MinPlayers = bg->GetMinPlayersPerTeam();
  233.                     uint32 qHorde = 0;
  234.                     uint32 qAlliance = 0;
  235.                     uint32 q_min_level = bracketEntry->minLevel;
  236.                     uint32 q_max_level = bracketEntry->maxLevel;
  237.                     GroupsQueueType::const_iterator itr;
  238.                    
  239.                     for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
  240.                         if (!(*itr)->IsInvitedToBGInstanceGUID)
  241.                             qAlliance += (*itr)->Players.size();
  242.                    
  243.                     for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
  244.                         if (!(*itr)->IsInvitedToBGInstanceGUID)
  245.                             qHorde += (*itr)->Players.size();
  246.  
  247.                     // Show queue status to player only (when joining queue)
  248.                     if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
  249.                     {
  250.                         ChatHandler(leader->GetSession()).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bgName, q_min_level, q_max_level,
  251.                         qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
  252.                     }
  253.                      // System message
  254.                     else
  255.                     {
  256.                         sWorld->SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level,
  257.                         qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
  258.                     }
  259.                 }
  260.             }
  261.         }
  262.         //release mutex
  263.     }
  264.  
  265.     return ginfo;
  266. }
  267.  
  268. void BattlegroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BattlegroundBracketId bracket_id)
  269. {
  270.     uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, getMSTime());
  271.     uint8 team_index = TEAM_ALLIANCE;                    //default set to TEAM_ALLIANCE - or non rated arenas!
  272.     if (!ginfo->ArenaType)
  273.     {
  274.         if (ginfo->Team == HORDE)
  275.             team_index = TEAM_HORDE;
  276.     }
  277.     else
  278.     {
  279.         if (ginfo->IsRated)
  280.             team_index = TEAM_HORDE;                     //for rated arenas use TEAM_HORDE
  281.     }
  282.  
  283.     //store pointer to arrayindex of player that was added first
  284.     uint32* lastPlayerAddedPointer = &(m_WaitTimeLastPlayer[team_index][bracket_id]);
  285.     //remove his time from sum
  286.     m_SumOfWaitTimes[team_index][bracket_id] -= m_WaitTimes[team_index][bracket_id][(*lastPlayerAddedPointer)];
  287.     //set average time to new
  288.     m_WaitTimes[team_index][bracket_id][(*lastPlayerAddedPointer)] = timeInQueue;
  289.     //add new time to sum
  290.     m_SumOfWaitTimes[team_index][bracket_id] += timeInQueue;
  291.     //set index of last player added to next one
  292.     (*lastPlayerAddedPointer)++;
  293.     (*lastPlayerAddedPointer) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME;
  294. }
  295.  
  296. uint32 BattlegroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BattlegroundBracketId bracket_id) const
  297. {
  298.     uint8 team_index = TEAM_ALLIANCE;                    //default set to TEAM_ALLIANCE - or non rated arenas!
  299.     if (!ginfo->ArenaType)
  300.     {
  301.         if (ginfo->Team == HORDE)
  302.             team_index = TEAM_HORDE;
  303.     }
  304.     else
  305.     {
  306.         if (ginfo->IsRated)
  307.             team_index = TEAM_HORDE;                     //for rated arenas use TEAM_HORDE
  308.     }
  309.     //check if there is enought values(we always add values > 0)
  310.     if (m_WaitTimes[team_index][bracket_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1])
  311.         return (m_SumOfWaitTimes[team_index][bracket_id] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME);
  312.     else
  313.         //if there aren't enough values return 0 - not available
  314.         return 0;
  315. }
  316.  
  317. //remove player from queue and from group info, if group info is empty then remove it too
  318. void BattlegroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
  319. {
  320.     int32 bracket_id = -1;                                     // signed for proper for-loop finish
  321.     QueuedPlayersMap::iterator itr;
  322.  
  323.     //remove player from map, if he's there
  324.     itr = m_QueuedPlayers.find(guid);
  325.     if (itr == m_QueuedPlayers.end())
  326.     {
  327.         std::string playerName = "Unknown";
  328.         if (Player* player = ObjectAccessor::FindPlayer(guid))
  329.             playerName = player->GetName();
  330.         TC_LOG_ERROR(LOG_FILTER_BATTLEGROUND, "BattlegroundQueue: couldn't find player %s (GUID: %u)", playerName.c_str(), GUID_LOPART(guid));
  331.         return;
  332.     }
  333.  
  334.     GroupQueueInfo* group = itr->second.GroupInfo;
  335.     GroupsQueueType::iterator group_itr;
  336.     // mostly people with the highest levels are in battlegrounds, thats why
  337.     // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0
  338.  
  339.     uint32 index = (group->Team == HORDE) ? BG_QUEUE_PREMADE_HORDE : BG_QUEUE_PREMADE_ALLIANCE;
  340.  
  341.     for (int32 bracket_id_tmp = MAX_BATTLEGROUND_BRACKETS - 1; bracket_id_tmp >= 0 && bracket_id == -1; --bracket_id_tmp)
  342.     {
  343.         //we must check premade and normal team's queue - because when players from premade are joining bg,
  344.         //they leave groupinfo so we can't use its players size to find out index
  345.         for (uint8 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; ++j)
  346.         {
  347.             GroupsQueueType::iterator k = m_QueuedGroups[bracket_id_tmp][j].begin();
  348.             for (; k != m_QueuedGroups[bracket_id_tmp][j].end(); ++k)
  349.             {
  350.                 if ((*k) == group)
  351.                 {
  352.                     bracket_id = bracket_id_tmp;
  353.                     group_itr = k;
  354.                     //we must store index to be able to erase iterator
  355.                     index = j;
  356.                     break;
  357.                 }
  358.             }
  359.         }
  360.     }
  361.  
  362.     //player can't be in queue without group, but just in case
  363.     if (bracket_id == -1)
  364.     {
  365.         TC_LOG_ERROR(LOG_FILTER_BATTLEGROUND, "BattlegroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid));
  366.         return;
  367.     }
  368.     TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "BattlegroundQueue: Removing player GUID %u, from bracket_id %u", GUID_LOPART(guid), (uint32)bracket_id);
  369.  
  370.     // ALL variables are correctly set
  371.     // We can ignore leveling up in queue - it should not cause crash
  372.     // remove player from group
  373.     // if only one player there, remove group
  374.  
  375.     // remove player queue info from group queue info
  376.     std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
  377.     if (pitr != group->Players.end())
  378.         group->Players.erase(pitr);
  379.  
  380.     // if invited to bg, and should decrease invited count, then do it
  381.     if (decreaseInvitedCount && group->IsInvitedToBGInstanceGUID)
  382.         if (Battleground* bg = sBattlegroundMgr->GetBattleground(group->IsInvitedToBGInstanceGUID, group->BgTypeId))
  383.             bg->DecreaseInvitedCount(group->Team);
  384.  
  385.     // remove player queue info
  386.     m_QueuedPlayers.erase(itr);
  387.  
  388.     // announce to world if arena team left queue for rated match, show only once
  389.     if (group->ArenaType && group->IsRated && group->Players.empty() && sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE))
  390.         if (ArenaTeam* Team = sArenaTeamMgr->GetArenaTeamById(group->ArenaTeamId))
  391.             sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, Team->GetName().c_str(), group->ArenaType, group->ArenaType, group->ArenaTeamRating);
  392.  
  393.     // if player leaves queue and he is invited to rated arena match, then he have to lose
  394.     if (group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount)
  395.     {
  396.         if (ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(group->ArenaTeamId))
  397.         {
  398.             TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating);
  399.             if (Player* player = ObjectAccessor::FindPlayer(guid))
  400.                 at->MemberLost(player, group->OpponentsMatchmakerRating);
  401.             else
  402.                 at->OfflineMemberLost(guid, group->OpponentsMatchmakerRating);
  403.             at->SaveToDB();
  404.         }
  405.     }
  406.  
  407.     // remove group queue info if needed
  408.     if (group->Players.empty())
  409.     {
  410.         m_QueuedGroups[bracket_id][index].erase(group_itr);
  411.         delete group;
  412.         return;
  413.     }
  414.  
  415.     // if group wasn't empty, so it wasn't deleted, and player have left a rated
  416.     // queue -> everyone from the group should leave too
  417.     // don't remove recursively if already invited to bg!
  418.     if (!group->IsInvitedToBGInstanceGUID && group->IsRated)
  419.     {
  420.         // remove next player, this is recursive
  421.         // first send removal information
  422.         if (Player* plr2 = ObjectAccessor::FindPlayer(group->Players.begin()->first))
  423.         {
  424.             Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(group->BgTypeId);
  425.             BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType);
  426.             uint32 queueSlot = plr2->GetBattlegroundQueueIndex(bgQueueTypeId);
  427.             plr2->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to
  428.                                                             // queue->removeplayer, it causes bugs
  429.             WorldPacket data;
  430.             sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0);
  431.             plr2->GetSession()->SendPacket(&data);
  432.         }
  433.         // then actually delete, this may delete the group as well!
  434.         RemovePlayer(group->Players.begin()->first, decreaseInvitedCount);
  435.     }
  436. }
  437.  
  438. //returns true when player pl_guid is in queue and is invited to bgInstanceGuid
  439. bool BattlegroundQueue::IsPlayerInvited(uint64 pl_guid, const uint32 bgInstanceGuid, const uint32 removeTime)
  440. {
  441.     QueuedPlayersMap::const_iterator qItr = m_QueuedPlayers.find(pl_guid);
  442.     return (qItr != m_QueuedPlayers.end()
  443.         && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == bgInstanceGuid
  444.         && qItr->second.GroupInfo->RemoveInviteTime == removeTime);
  445. }
  446.  
  447. bool BattlegroundQueue::GetPlayerGroupInfoData(uint64 guid, GroupQueueInfo* ginfo)
  448. {
  449.     QueuedPlayersMap::const_iterator qItr = m_QueuedPlayers.find(guid);
  450.     if (qItr == m_QueuedPlayers.end())
  451.         return false;
  452.     *ginfo = *(qItr->second.GroupInfo);
  453.     return true;
  454. }
  455.  
  456. uint32 BattlegroundQueue::GetPlayersInQueue(TeamId id)
  457. {
  458.     return m_SelectionPools[id].GetPlayerCount();
  459. }
  460.  
  461. bool BattlegroundQueue::InviteGroupToBG(GroupQueueInfo* ginfo, Battleground* bg, uint32 side)
  462. {
  463.     // set side if needed
  464.     if (side)
  465.         ginfo->Team = side;
  466.  
  467.     if (!ginfo->IsInvitedToBGInstanceGUID)
  468.     {
  469.         // not yet invited
  470.         // set invitation
  471.         ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
  472.         BattlegroundTypeId bgTypeId = bg->GetTypeID();
  473.         BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, bg->GetArenaType());
  474.         BattlegroundBracketId bracket_id = bg->GetBracketId();
  475.  
  476.         // set ArenaTeamId for rated matches
  477.         if (bg->isArena() && bg->isRated())
  478.             bg->SetArenaTeamIdForTeam(ginfo->Team, ginfo->ArenaTeamId);
  479.  
  480.         ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME;
  481.  
  482.         // loop through the players
  483.         for (std::map<uint64, PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
  484.         {
  485.             // get the player
  486.             Player* player = ObjectAccessor::FindPlayer(itr->first);
  487.             // if offline, skip him, this should not happen - player is removed from queue when he logs out
  488.             if (!player)
  489.                 continue;
  490.  
  491.             // invite the player
  492.             PlayerInvitedToBGUpdateAverageWaitTime(ginfo, bracket_id);
  493.             //sBattlegroundMgr->InvitePlayer(player, bg, ginfo->Team);
  494.  
  495.             // set invited player counters
  496.             bg->IncreaseInvitedCount(ginfo->Team);
  497.  
  498.             player->SetInviteForBattlegroundQueueType(bgQueueTypeId, ginfo->IsInvitedToBGInstanceGUID);
  499.  
  500.             // create remind invite events
  501.             BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(player->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->ArenaType, ginfo->RemoveInviteTime);
  502.             m_events.AddEvent(inviteEvent, m_events.CalculateTime(INVITATION_REMIND_TIME));
  503.             // create automatic remove events
  504.             BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(player->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, bgQueueTypeId, ginfo->RemoveInviteTime);
  505.             m_events.AddEvent(removeEvent, m_events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
  506.  
  507.             WorldPacket data;
  508.  
  509.             uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId);
  510.  
  511.             TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "Battleground: invited player %s (%u) to BG instance %u queueindex %u bgtype %u",
  512.                  player->GetName().c_str(), player->GetGUIDLow(), bg->GetInstanceID(), queueSlot, bg->GetTypeID());
  513.  
  514.             // send status packet
  515.             sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType, 0);
  516.             player->GetSession()->SendPacket(&data);
  517.         }
  518.         return true;
  519.     }
  520.  
  521.     return false;
  522. }
  523.  
  524. /*
  525. This function is inviting players to already running battlegrounds
  526. Invitation type is based on config file
  527. large groups are disadvantageous, because they will be kicked first if invitation type = 1
  528. */
  529. void BattlegroundQueue::FillPlayersToBG(Battleground* bg, BattlegroundBracketId bracket_id)
  530. {
  531.     int32 hordeFree = bg->GetFreeSlotsForTeam(HORDE);
  532.     int32 aliFree   = bg->GetFreeSlotsForTeam(ALLIANCE);
  533.  
  534.     if (!bg->isArena())
  535.         if (FillXPlayersToBG(bracket_id, bg, false))
  536.             return;
  537.  
  538.     //iterator for iterating through bg queue
  539.     GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].begin();
  540.     //count of groups in queue - used to stop cycles
  541.     uint32 aliCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].size();
  542.     //index to queue which group is current
  543.     uint32 aliIndex = 0;
  544.     for (; aliIndex < aliCount && m_SelectionPools[TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++)
  545.         ++Ali_itr;
  546.     //the same thing for horde
  547.     GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].begin();
  548.     uint32 hordeCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].size();
  549.     uint32 hordeIndex = 0;
  550.     for (; hordeIndex < hordeCount && m_SelectionPools[TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++)
  551.         ++Horde_itr;
  552.  
  553.     //if ofc like BG queue invitation is set in config, then we are happy
  554.     if (sWorld->getIntConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == 0)
  555.         return;
  556.  
  557.     /*
  558.     if we reached this code, then we have to solve NP - complete problem called Subset sum problem
  559.     So one solution is to check all possible invitation subgroups, or we can use these conditions:
  560.     1. Last time when BattlegroundQueue::Update was executed we invited all possible players - so there is only small possibility
  561.         that we will invite now whole queue, because only 1 change has been made to queues from the last BattlegroundQueue::Update call
  562.     2. Other thing we should consider is group order in queue
  563.     */
  564.  
  565.     // At first we need to compare free space in bg and our selection pool
  566.     int32 diffAli   = aliFree   - int32(m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount());
  567.     int32 diffHorde = hordeFree - int32(m_SelectionPools[TEAM_HORDE].GetPlayerCount());
  568.     while (abs(diffAli - diffHorde) > 1 && (m_SelectionPools[TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() > 0))
  569.     {
  570.         //each cycle execution we need to kick at least 1 group
  571.         if (diffAli < diffHorde)
  572.         {
  573.             //kick alliance group, add to pool new group if needed
  574.             if (m_SelectionPools[TEAM_ALLIANCE].KickGroup(diffHorde - diffAli))
  575.             {
  576.                 for (; aliIndex < aliCount && m_SelectionPools[TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++)
  577.                     ++Ali_itr;
  578.             }
  579.             //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break;
  580.             if (!m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount())
  581.             {
  582.                 if (aliFree <= diffHorde + 1)
  583.                     break;
  584.                 m_SelectionPools[TEAM_HORDE].KickGroup(diffHorde - diffAli);
  585.             }
  586.         }
  587.         else
  588.         {
  589.             //kick horde group, add to pool new group if needed
  590.             if (m_SelectionPools[TEAM_HORDE].KickGroup(diffAli - diffHorde))
  591.             {
  592.                 for (; hordeIndex < hordeCount && m_SelectionPools[TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++)
  593.                     ++Horde_itr;
  594.             }
  595.             if (!m_SelectionPools[TEAM_HORDE].GetPlayerCount())
  596.             {
  597.                 if (hordeFree <= diffAli + 1)
  598.                     break;
  599.                 m_SelectionPools[TEAM_ALLIANCE].KickGroup(diffAli - diffHorde);
  600.             }
  601.         }
  602.         //count diffs after small update
  603.         diffAli   = aliFree   - int32(m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount());
  604.         diffHorde = hordeFree - int32(m_SelectionPools[TEAM_HORDE].GetPlayerCount());
  605.     }
  606. }
  607.  
  608. // this method checks if premade versus premade battleground is possible
  609. // then after 30 mins (default) in queue it moves premade group to normal queue
  610. // it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players
  611. bool BattlegroundQueue::CheckPremadeMatch(BattlegroundBracketId bracket_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
  612. {
  613.     //check match
  614.     if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty())
  615.     {
  616.         //start premade match
  617.         //if groups aren't invited
  618.         GroupsQueueType::const_iterator ali_group, horde_group;
  619.         for (ali_group = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); ali_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++ali_group)
  620.             if (!(*ali_group)->IsInvitedToBGInstanceGUID)
  621.                 break;
  622.         for (horde_group = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].begin(); horde_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].end(); ++horde_group)
  623.             if (!(*horde_group)->IsInvitedToBGInstanceGUID)
  624.                 break;
  625.  
  626.         if (ali_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].end())
  627.         {
  628.             m_SelectionPools[TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
  629.             m_SelectionPools[TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
  630.             //add groups/players from normal queue to size of bigger group
  631.             uint32 maxPlayers = std::min(m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[TEAM_HORDE].GetPlayerCount());
  632.             GroupsQueueType::const_iterator itr;
  633.             for (uint32 i = 0; i < BG_TEAMS_COUNT; i++)
  634.             {
  635.                 for (itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
  636.                 {
  637.                     //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
  638.                     if (!(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers))
  639.                         break;
  640.                 }
  641.             }
  642.             //premade selection pools are set
  643.             return true;
  644.         }
  645.     }
  646.     // now check if we can move group from Premade queue to normal queue (timer has expired) or group size lowered!!
  647.     // this could be 2 cycles but i'm checking only first team in queue - it can cause problem -
  648.     // if first is invited to BG and seconds timer expired, but we can ignore it, because players have only 80 seconds to click to enter bg
  649.     // and when they click or after 80 seconds the queue info is removed from queue
  650.     uint32 time_before = getMSTime() - sWorld->getIntConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
  651.     for (uint32 i = 0; i < BG_TEAMS_COUNT; i++)
  652.     {
  653.         if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
  654.         {
  655.             GroupsQueueType::iterator itr = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin();
  656.             if (!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam))
  657.             {
  658.                 //we must insert group to normal queue and erase pointer from premade queue
  659.                 m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
  660.                 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr);
  661.             }
  662.         }
  663.     }
  664.     //selection pools are not set
  665.     return false;
  666. }
  667.  
  668. // this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
  669. bool BattlegroundQueue::CheckNormalMatch(Battleground* bg_template, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers)
  670. {
  671.     GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
  672.     for (uint32 i = 0; i < BG_TEAMS_COUNT; i++)
  673.     {
  674.         itr_team[i] = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
  675.         for (; itr_team[i] != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i]))
  676.         {
  677.             if (!(*(itr_team[i]))->IsInvitedToBGInstanceGUID)
  678.             {
  679.                 m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers);
  680.                 if (m_SelectionPools[i].GetPlayerCount() >= minPlayers)
  681.                     break;
  682.             }
  683.         }
  684.     }
  685.     //try to invite same number of players - this cycle may cause longer wait time even if there are enough players in queue, but we want ballanced bg
  686.     uint32 j = TEAM_ALLIANCE;
  687.     if (m_SelectionPools[TEAM_HORDE].GetPlayerCount() < m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount())
  688.         j = TEAM_HORDE;
  689.     if (sWorld->getIntConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != 0
  690.         && m_SelectionPools[TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() >= minPlayers)
  691.     {
  692.         //we will try to invite more groups to team with less players indexed by j
  693.         ++(itr_team[j]);                                         //this will not cause a crash, because for cycle above reached break;
  694.         for (; itr_team[j] != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
  695.         {
  696.             if (!(*(itr_team[j]))->IsInvitedToBGInstanceGUID)
  697.                 if (!m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()))
  698.                     break;
  699.         }
  700.         // do not allow to start bg with more than 2 players more on 1 faction
  701.         if (abs((int32)(m_SelectionPools[TEAM_HORDE].GetPlayerCount() - m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount())) > 2)
  702.             return false;
  703.     }
  704.     //allow 1v0 if debug bg
  705.     if (sBattlegroundMgr->isTesting() && bg_template->isBattleground() && (m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[TEAM_HORDE].GetPlayerCount()))
  706.         return true;
  707.     //return true if there are enough players in selection pools - enable to work .debug bg command correctly
  708.     return m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[TEAM_HORDE].GetPlayerCount() >= minPlayers;
  709. }
  710.  
  711. // this method will check if we can invite players to same faction skirmish match
  712. bool BattlegroundQueue::CheckSkirmishForSameFaction(BattlegroundBracketId bracket_id, uint32 minPlayersPerTeam)
  713. {
  714.     if (m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam)
  715.         return false;
  716.     uint32 teamIndex = TEAM_ALLIANCE;
  717.     uint32 otherTeam = TEAM_HORDE;
  718.     uint32 otherTeamId = HORDE;
  719.     if (m_SelectionPools[TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam)
  720.     {
  721.         teamIndex = TEAM_HORDE;
  722.         otherTeam = TEAM_ALLIANCE;
  723.         otherTeamId = ALLIANCE;
  724.     }
  725.     //clear other team's selection
  726.     m_SelectionPools[otherTeam].Init();
  727.     //store last ginfo pointer
  728.     GroupQueueInfo* ginfo = m_SelectionPools[teamIndex].SelectedGroups.back();
  729.     //set itr_team to group that was added to selection pool latest
  730.     GroupsQueueType::iterator itr_team = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin();
  731.     for (; itr_team != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team)
  732.         if (ginfo == *itr_team)
  733.             break;
  734.     if (itr_team == m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end())
  735.         return false;
  736.     GroupsQueueType::iterator itr_team2 = itr_team;
  737.     ++itr_team2;
  738.     //invite players to other selection pool
  739.     for (; itr_team2 != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team2)
  740.     {
  741.         //if selection pool is full then break;
  742.         if (!(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam))
  743.             break;
  744.     }
  745.     if (m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam)
  746.         return false;
  747.  
  748.     //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue
  749.     for (GroupsQueueType::iterator itr = m_SelectionPools[otherTeam].SelectedGroups.begin(); itr != m_SelectionPools[otherTeam].SelectedGroups.end(); ++itr)
  750.     {
  751.         //set correct team
  752.         (*itr)->Team = otherTeamId;
  753.         //add team to other queue
  754.         m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + otherTeam].push_front(*itr);
  755.         //remove team from old queue
  756.         GroupsQueueType::iterator itr2 = itr_team;
  757.         ++itr2;
  758.         for (; itr2 != m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2)
  759.         {
  760.             if (*itr2 == *itr)
  761.             {
  762.                 m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].erase(itr2);
  763.                 break;
  764.             }
  765.         }
  766.     }
  767.     return true;
  768. }
  769.  
  770. void BattlegroundQueue::UpdateEvents(uint32 diff)
  771. {
  772.     m_events.Update(diff);
  773. }
  774.  
  775. /*
  776. this method is called when group is inserted, or player / group is removed from BG Queue - there is only one player's status changed, so we don't use while (true) cycles to invite whole queue
  777. it must be called after fully adding the members of a group to ensure group joining
  778. should be called from Battleground::RemovePlayer function in some cases
  779. */
  780. void BattlegroundQueue::BattlegroundQueueUpdate(uint32 /*diff*/, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id, uint8 arenaType, bool isRated, uint32 arenaRating)
  781. {
  782.     //if no players in queue - do nothing
  783.     if (m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
  784.         m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty() &&
  785.         m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
  786.         m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].empty() &&
  787.         m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].empty())
  788.         return;
  789.  
  790.     // battleground with free slot for player should be always in the beggining of the queue
  791.     // maybe it would be better to create bgfreeslotqueue for each bracket_id
  792.     BGFreeSlotQueueContainer& bgQueues = sBattlegroundMgr->GetBGFreeSlotQueueStore(bgTypeId);
  793.     for (BGFreeSlotQueueContainer::iterator itr = bgQueues.begin(); itr != bgQueues.end();)
  794.     {
  795.         Battleground* bg = *itr; ++itr;
  796.         // DO NOT allow queue manager to invite new player to rated games
  797.         if (!bg->isRated() && bg->GetTypeID() == bgTypeId && bg->GetBracketId() == bracket_id &&
  798.             bg->GetStatus() > STATUS_WAIT_QUEUE && bg->GetStatus() < STATUS_WAIT_LEAVE)
  799.         {
  800.             // clear selection pools
  801.             m_SelectionPools[TEAM_ALLIANCE].Init();
  802.             m_SelectionPools[TEAM_HORDE].Init();
  803.  
  804.             // call a function that does the job for us
  805.             FillPlayersToBG(bg, bracket_id);
  806.  
  807.             // now everything is set, invite players
  808.             for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_ALLIANCE].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_ALLIANCE].SelectedGroups.end(); ++citr)
  809.                 InviteGroupToBG((*citr), bg, (*citr)->Team);
  810.  
  811.             for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_HORDE].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_HORDE].SelectedGroups.end(); ++citr)
  812.                 InviteGroupToBG((*citr), bg, (*citr)->Team);
  813.  
  814.             if (!bg->HasFreeSlots())
  815.                 bg->RemoveFromBGFreeSlotQueue();
  816.         }
  817.     }
  818.  
  819.     // finished iterating through the bgs with free slots, maybe we need to create a new bg
  820.  
  821.     Battleground* bg_template = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
  822.     if (!bg_template)
  823.     {
  824.         TC_LOG_ERROR(LOG_FILTER_BATTLEGROUND, "Battleground: Update: bg template not found for %u", bgTypeId);
  825.         return;
  826.     }
  827.  
  828.     PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketById(bg_template->GetMapId(), bracket_id);
  829.     if (!bracketEntry)
  830.     {
  831.         TC_LOG_ERROR(LOG_FILTER_BATTLEGROUND, "Battleground: Update: bg bracket entry not found for map %u bracket id %u", bg_template->GetMapId(), bracket_id);
  832.         return;
  833.     }
  834.  
  835.     // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
  836.     uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
  837.     uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
  838.  
  839.     if (bg_template->isArena())
  840.     {
  841.         MaxPlayersPerTeam = arenaType;
  842.         MinPlayersPerTeam = sBattlegroundMgr->isArenaTesting() ? 1 : arenaType;
  843.     }
  844.     else if (sBattlegroundMgr->isTesting())
  845.         MinPlayersPerTeam = 1;
  846.  
  847.     m_SelectionPools[TEAM_ALLIANCE].Init();
  848.     m_SelectionPools[TEAM_HORDE].Init();
  849.  
  850.     if (bg_template->isBattleground())
  851.     {
  852.         if (CheckPremadeMatch(bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam))
  853.         {
  854.             // create new battleground
  855.             Battleground* bg2 = sBattlegroundMgr->CreateNewBattleground(bgTypeId, bracketEntry, 0, false);
  856.             if (!bg2)
  857.             {
  858.                 TC_LOG_ERROR(LOG_FILTER_BATTLEGROUND, "BattlegroundQueue::Update - Cannot create battleground: %u", bgTypeId);
  859.                 return;
  860.             }
  861.             // invite those selection pools
  862.             for (uint32 i = 0; i < BG_TEAMS_COUNT; i++)
  863.                 for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
  864.                     InviteGroupToBG((*citr), bg2, (*citr)->Team);
  865.  
  866.             bg2->StartBattleground();
  867.             //clear structures
  868.             m_SelectionPools[TEAM_ALLIANCE].Init();
  869.             m_SelectionPools[TEAM_HORDE].Init();
  870.         }
  871.     }
  872.  
  873.     // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
  874.     if (!isRated)
  875.     {
  876.         // if there are enough players in pools, start new battleground or non rated arena
  877.         if (CheckNormalMatch(bg_template, bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam)
  878.             || (bg_template->isArena() && CheckSkirmishForSameFaction(bracket_id, MinPlayersPerTeam))
  879.             || CheckCrossFactionMatch(bracket_id, bg_template))
  880.         {
  881.             // we successfully created a pool
  882.             Battleground* bg2 = sBattlegroundMgr->CreateNewBattleground(bgTypeId, bracketEntry, arenaType, false);
  883.             if (!bg2)
  884.             {
  885.                 TC_LOG_ERROR(LOG_FILTER_BATTLEGROUND, "BattlegroundQueue::Update - Cannot create battleground: %u", bgTypeId);
  886.                 return;
  887.             }
  888.  
  889.             // invite those selection pools
  890.             for (uint32 i = 0; i < BG_TEAMS_COUNT; i++)
  891.                 for (GroupsQueueType::const_iterator citr = m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
  892.                     InviteGroupToBG((*citr), bg2, (*citr)->Team);
  893.             // start bg
  894.             bg2->StartBattleground();
  895.         }
  896.     }
  897.     else if (bg_template->isArena())
  898.     {
  899.         // found out the minimum and maximum ratings the newly added team should battle against
  900.         // arenaRating is the rating of the latest joined team, or 0
  901.         // 0 is on (automatic update call) and we must set it to team's with longest wait time
  902.         if (!arenaRating)
  903.         {
  904.             GroupQueueInfo* front1 = NULL;
  905.             GroupQueueInfo* front2 = NULL;
  906.             if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty())
  907.             {
  908.                 front1 = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].front();
  909.                 arenaRating = front1->ArenaMatchmakerRating;
  910.             }
  911.             if (!m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty())
  912.             {
  913.                 front2 = m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].front();
  914.                 arenaRating = front2->ArenaMatchmakerRating;
  915.             }
  916.             if (front1 && front2)
  917.             {
  918.                 if (front1->JoinTime < front2->JoinTime)
  919.                     arenaRating = front1->ArenaMatchmakerRating;
  920.             }
  921.             else if (!front1 && !front2)
  922.                 return; //queues are empty
  923.         }
  924.  
  925.         //set rating range
  926.         uint32 arenaMinRating = (arenaRating <= sBattlegroundMgr->GetMaxRatingDifference()) ? 0 : arenaRating - sBattlegroundMgr->GetMaxRatingDifference();
  927.         uint32 arenaMaxRating = arenaRating + sBattlegroundMgr->GetMaxRatingDifference();
  928.         // if max rating difference is set and the time past since server startup is greater than the rating discard time
  929.         // (after what time the ratings aren't taken into account when making teams) then
  930.         // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
  931.         // else leave the discard time on 0, this way all ratings will be discarded
  932.         uint32 discardTime = getMSTime() - sBattlegroundMgr->GetRatingDiscardTimer();
  933.  
  934.         // we need to find 2 teams which will play next game
  935.         GroupsQueueType::iterator itr_teams[BG_TEAMS_COUNT];
  936.         uint8 found = 0;
  937.         uint8 team = 0;
  938.  
  939.         for (uint8 i = BG_QUEUE_PREMADE_ALLIANCE; i < BG_QUEUE_NORMAL_ALLIANCE; i++)
  940.         {
  941.             // take the group that joined first
  942.             GroupsQueueType::iterator itr2 = m_QueuedGroups[bracket_id][i].begin();
  943.             for (; itr2 != m_QueuedGroups[bracket_id][i].end(); ++itr2)
  944.             {
  945.                 // if group match conditions, then add it to pool
  946.                 if (!(*itr2)->IsInvitedToBGInstanceGUID
  947.                     && (((*itr2)->ArenaMatchmakerRating >= arenaMinRating && (*itr2)->ArenaMatchmakerRating <= arenaMaxRating)
  948.                         || (*itr2)->JoinTime < discardTime))
  949.                 {
  950.                     itr_teams[found++] = itr2;
  951.                     team = i;
  952.                     break;
  953.                 }
  954.             }
  955.         }
  956.  
  957.         if (!found)
  958.             return;
  959.  
  960.         if (found == 1)
  961.         {
  962.             for (GroupsQueueType::iterator itr3 = itr_teams[0]; itr3 != m_QueuedGroups[bracket_id][team].end(); ++itr3)
  963.             {
  964.                 if (!(*itr3)->IsInvitedToBGInstanceGUID
  965.                     && (((*itr3)->ArenaMatchmakerRating >= arenaMinRating && (*itr3)->ArenaMatchmakerRating <= arenaMaxRating)
  966.                         || (*itr3)->JoinTime < discardTime)
  967.                     && (*itr_teams[0])->ArenaTeamId != (*itr3)->ArenaTeamId)
  968.                 {
  969.                     itr_teams[found++] = itr3;
  970.                     break;
  971.                 }
  972.             }
  973.         }
  974.  
  975.         //if we have 2 teams, then start new arena and invite players!
  976.         if (found == 2)
  977.         {
  978.             GroupQueueInfo* aTeam = *itr_teams[TEAM_ALLIANCE];
  979.             GroupQueueInfo* hTeam = *itr_teams[TEAM_HORDE];
  980.             Battleground* arena = sBattlegroundMgr->CreateNewBattleground(bgTypeId, bracketEntry, arenaType, true);
  981.             if (!arena)
  982.             {
  983.                 TC_LOG_ERROR(LOG_FILTER_BATTLEGROUND, "BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
  984.                 return;
  985.             }
  986.  
  987.             aTeam->OpponentsTeamRating = hTeam->ArenaTeamRating;
  988.             hTeam->OpponentsTeamRating = aTeam->ArenaTeamRating;
  989.             aTeam->OpponentsMatchmakerRating = hTeam->ArenaMatchmakerRating;
  990.             hTeam->OpponentsMatchmakerRating = aTeam->ArenaMatchmakerRating;
  991.             TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "setting oposite teamrating for team %u to %u", aTeam->ArenaTeamId, aTeam->OpponentsTeamRating);
  992.             TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "setting oposite teamrating for team %u to %u", hTeam->ArenaTeamId, hTeam->OpponentsTeamRating);
  993.  
  994.             // now we must move team if we changed its faction to another faction queue, because then we will spam log by errors in Queue::RemovePlayer
  995.             if (aTeam->Team != ALLIANCE)
  996.             {
  997.                 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(aTeam);
  998.                 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].erase(itr_teams[TEAM_ALLIANCE]);
  999.             }
  1000.             if (hTeam->Team != HORDE)
  1001.             {
  1002.                 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].push_front(hTeam);
  1003.                 m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_teams[TEAM_HORDE]);
  1004.             }
  1005.  
  1006.             arena->SetArenaMatchmakerRating(ALLIANCE, aTeam->ArenaMatchmakerRating);
  1007.             arena->SetArenaMatchmakerRating(   HORDE, hTeam->ArenaMatchmakerRating);
  1008.             InviteGroupToBG(aTeam, arena, ALLIANCE);
  1009.             InviteGroupToBG(hTeam, arena, HORDE);
  1010.  
  1011.             TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "Starting rated arena match!");
  1012.             arena->StartBattleground();
  1013.         }
  1014.     }
  1015. }
  1016.  
  1017. /*********************************************************/
  1018. /***            BATTLEGROUND QUEUE EVENTS              ***/
  1019. /*********************************************************/
  1020.  
  1021. bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
  1022. {
  1023.     Player* player = ObjectAccessor::FindPlayer(m_PlayerGuid);
  1024.     // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
  1025.     if (!player)
  1026.         return true;
  1027.  
  1028.     Battleground* bg = sBattlegroundMgr->GetBattleground(m_BgInstanceGUID, m_BgTypeId);
  1029.     //if battleground ended and its instance deleted - do nothing
  1030.     if (!bg)
  1031.         return true;
  1032.  
  1033.     BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
  1034.     uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId);
  1035.     if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES)         // player is in queue or in battleground
  1036.     {
  1037.         // check if player is invited to this bg
  1038.         BattlegroundQueue &bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
  1039.         if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime))
  1040.         {
  1041.             WorldPacket data;
  1042.             //we must send remaining time in queue
  1043.             sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, m_ArenaType, 0);
  1044.             player->GetSession()->SendPacket(&data);
  1045.         }
  1046.     }
  1047.     return true;                                            //event will be deleted
  1048. }
  1049.  
  1050. void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
  1051. {
  1052.     //do nothing
  1053. }
  1054.  
  1055. /*
  1056.     this event has many possibilities when it is executed:
  1057.     1. player is in battleground (he clicked enter on invitation window)
  1058.     2. player left battleground queue and he isn't there any more
  1059.     3. player left battleground queue and he joined it again and IsInvitedToBGInstanceGUID = 0
  1060.     4. player left queue and he joined again and he has been invited to same battleground again -> we should not remove him from queue yet
  1061.     5. player is invited to bg and he didn't choose what to do and timer expired - only in this condition we should call queue::RemovePlayer
  1062.     we must remove player in the 5. case even if battleground object doesn't exist!
  1063. */
  1064. bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
  1065. {
  1066.     Player* player = ObjectAccessor::FindPlayer(m_PlayerGuid);
  1067.     if (!player)
  1068.         // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
  1069.         return true;
  1070.  
  1071.     Battleground* bg = sBattlegroundMgr->GetBattleground(m_BgInstanceGUID, m_BgTypeId);
  1072.     //battleground can be deleted already when we are removing queue info
  1073.     //bg pointer can be NULL! so use it carefully!
  1074.  
  1075.     uint32 queueSlot = player->GetBattlegroundQueueIndex(m_BgQueueTypeId);
  1076.     if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES)         // player is in queue, or in Battleground
  1077.     {
  1078.         // check if player is in queue for this BG and if we are removing his invite event
  1079.         BattlegroundQueue &bgQueue = sBattlegroundMgr->GetBattlegroundQueue(m_BgQueueTypeId);
  1080.         if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime))
  1081.         {
  1082.             TC_LOG_DEBUG(LOG_FILTER_BATTLEGROUND, "Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.", player->GetGUIDLow(), m_BgInstanceGUID);
  1083.  
  1084.             player->RemoveBattlegroundQueueId(m_BgQueueTypeId);
  1085.             bgQueue.RemovePlayer(m_PlayerGuid, true);
  1086.             //update queues if battleground isn't ended
  1087.             if (bg && bg->isBattleground() && bg->GetStatus() != STATUS_WAIT_LEAVE)
  1088.                 sBattlegroundMgr->ScheduleQueueUpdate(0, 0, m_BgQueueTypeId, m_BgTypeId, bg->GetBracketId());
  1089.  
  1090.             WorldPacket data;
  1091.             sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0);
  1092.             player->GetSession()->SendPacket(&data);
  1093.         }
  1094.     }
  1095.  
  1096.     //event will be deleted
  1097.     return true;
  1098. }
  1099.  
  1100. void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
  1101. {
  1102.     //do nothing
  1103. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement