22 uint8 const LFG_FLEX_RAID_MIN_PLAYERS = 10;
26 return std::find(queue.begin(), queue.end(), guid) != queue.end();
29 bool CompatibleKeyContainsGuid(std::string
const& key,
uint64 guid)
31 std::ostringstream out;
33 std::string guidString = out.str();
35 std::string::size_type tokenStart = 0;
36 while (tokenStart <= key.length())
38 std::string::size_type tokenEnd = key.find(
'|', tokenStart);
39 std::string::size_type tokenLength = tokenEnd == std::string::npos ? std::string::npos : tokenEnd - tokenStart;
40 if (key.compare(tokenStart, tokenLength, guidString) == 0)
43 if (tokenEnd == std::string::npos)
46 tokenStart = tokenEnd + 1;
64 bool IsScenarioDifficulty(
uint32 difficulty)
69 bool IsScenarioDungeon(
uint32 dungeonId)
82 bool IsFlexibleRaidDungeon(
uint32 dungeonId)
89 return map && map->
IsRaid();
98 if (IsScenarioDungeon(dungeonId))
101 if (difficulty->maxPlayers)
107 if (IsFlexibleRaidDungeon(dungeonId))
110 if (difficulty->maxPlayers)
121 for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it)
122 if (IsScenarioDungeon(*it))
130 for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it)
131 if (IsFlexibleRaidDungeon(*it))
139 if (IsFlexibleRaidDungeon(dungeonId))
140 return sLFGMgr->IsDebugFlexRaidMinimumOverrideEnabled() ? 1 : LFG_FLEX_RAID_MIN_PLAYERS;
142 return GetDungeonMaxGroupSize(dungeonId);
149 for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it)
151 uint8 dungeonMinSize = GetDungeonMinGroupSize(*it);
152 uint8 dungeonMaxSize = GetDungeonMaxGroupSize(*it);
153 if (!minSize || dungeonMinSize < minSize)
154 minSize = dungeonMinSize;
155 if (!maxSize || dungeonMaxSize < maxSize)
156 maxSize = dungeonMaxSize;
169 GetQueueGroupSizeRange(dungeons, minSize, maxSize);
177 GetQueueGroupSizeRange(dungeons, minSize, maxSize);
183 if (HasScenarioDungeon(dungeons))
186 if (HasFlexibleRaidDungeon(dungeons))
194 if (HasScenarioDungeon(dungeons))
196 uint8 groupSize = GetQueueMaxGroupSize(dungeons);
199 dps = roles.size() >= groupSize ? 0 :
uint8(groupSize - roles.size());
203 if (HasFlexibleRaidDungeon(dungeons))
205 uint8 groupSize = GetQueueMaxGroupSize(dungeons);
208 dps = roles.size() >= groupSize ? 0 :
uint8(groupSize - roles.size());
218 for (LfgRolesMap::const_iterator it = assignedRoles.begin(); it != assignedRoles.end(); ++it)
219 ConsumeRoleSlot(it->second, tanks, healers, dps);
221 for (LfgRolesMap::const_iterator it = roles.begin(); it != roles.end(); ++it)
222 ConsumeRoleSlot(it->second, tanks, healers, dps);
254 std::ostringstream o;
256 LfgGuidSet::const_iterator it = guids.begin();
258 for (++it; it != guids.end(); ++it)
271 return "Compatibles (Bad States)";
275 return "Compatibles (Not enough players)";
277 return "Has ignores";
279 return "Multiple Lfg Groups";
281 return "Incompatible dungeons";
283 return "Incompatible roles";
285 return "Too much players";
287 return "Wrong group size";
295 LfgQueueDataContainer::iterator itQueue =
QueueDataStore.find(guid);
316 if (itr->first != guid)
318 if (CompatibleKeyContainsGuid(itr->second.bestCompatible, guid))
320 itr->second.bestCompatible.clear();
409 LfgCompatibleContainer::iterator it = itNext++;
410 if (CompatibleKeyContainsGuid(it->first, guid))
442 return itr->second.compatibility;
451 return &(itr->second);
465 firstNew.push_back(frontguid);
497 SF_LOG_DEBUG(
"lfg.queue.match.check",
"Guids: (%s) cached bad states are now valid, rebuilding compatibility", strGuids.c_str());
508 check.push_back(all.front());
535 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s): Size wrong - Not compatibles", strGuids.c_str());
540 for (LfgGuidList::const_iterator it = check.begin(); it != check.end(); ++it)
542 LfgQueueDataContainer::const_iterator itQueue =
QueueDataStore.find(*it);
543 if (itQueue !=
QueueDataStore.end() && HasFlexibleRaidDungeon(itQueue->second.dungeons))
550 if (check.size() > checkGroupLimit)
552 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s): Size wrong - Not compatibles", strGuids.c_str());
557 if (check.size() > 2)
559 uint64 frontGuid = check.front();
566 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) child %s not compatibles", strGuids.c_str(),
ConcatenateGuids(check).c_str());
568 return child_compatibles;
570 check.push_front(frontGuid);
574 uint8 numPlayers = 0;
575 uint8 numLfgGroups = 0;
576 for (LfgGuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= checkGroupLimit; ++it)
579 LfgQueueDataContainer::iterator itQueue =
QueueDataStore.find(guid);
582 SF_LOG_ERROR(
"lfg.queue.match.compatibility.check",
"Guid: [%u] is not queued but listed as queued!",
GUID_LOPART(guid));
588 for (LfgRolesMap::const_iterator it2 = itQueue->second.roles.begin(); it2 != itQueue->second.roles.end(); ++it2)
589 proposalGroups[it2->first] =
IS_GROUP_GUID(itQueue->first) ? itQueue->first : 0;
591 numPlayers += itQueue->second.roles.size();
596 proposal.
group = guid;
602 if (check.size() == 1)
604 LfgQueueDataContainer::iterator itQueue =
QueueDataStore.find(check.front());
605 uint8 minGroupSize = GetQueueMinGroupSize(itQueue->second.dungeons);
607 if (numPlayers < minGroupSize)
609 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) single group. Compatibles", strGuids.c_str());
612 data.
roles = itQueue->second.roles;
613 if (!CheckQueueRoles(data.
roles, itQueue->second.dungeons))
615 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) single group has invalid roles", strGuids.c_str());
626 if (numLfgGroups > 1)
628 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) More than one Lfggroup (%u)", strGuids.c_str(), numLfgGroups);
634 if (check.size() > 1)
636 for (LfgGuidList::const_iterator it = check.begin(); it != check.end(); ++it)
639 for (LfgRolesMap::const_iterator itRoles = roles.begin(); itRoles != roles.end(); ++itRoles)
641 LfgRolesMap::const_iterator itPlayer;
642 for (itPlayer = proposalRoles.begin(); itPlayer != proposalRoles.end(); ++itPlayer)
644 if (itRoles->first == itPlayer->first)
646 SF_LOG_ERROR(
"lfg.queue.match.compatibility.check",
"Guids: ERROR! Player multiple times in queue! [%u]",
GUID_LOPART(itRoles->first));
648 else if (
sLFGMgr->HasIgnore(itRoles->first, itPlayer->first))
651 if (itPlayer == proposalRoles.end())
652 proposalRoles[itRoles->first] = itRoles->second;
656 if (
uint8 playersize = numPlayers - proposalRoles.size())
658 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) not compatible, %u players are ignoring each other", strGuids.c_str(), playersize);
663 LfgGuidList::iterator itguid = check.begin();
665 std::ostringstream o;
667 for (++itguid; itguid != check.end(); ++itguid)
672 std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin()));
673 proposalDungeons = temporal;
676 if (proposalDungeons.empty())
678 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) No compatible dungeons%s", strGuids.c_str(), o.str().c_str());
684 if (!CheckQueueRoles(proposalRoles, proposalDungeons))
686 std::ostringstream rolesDebug;
687 for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it)
688 rolesDebug <<
", " << it->first <<
": " <<
GetRolesString(it->second);
690 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) Roles not compatible%s", strGuids.c_str(), rolesDebug.str().c_str());
697 uint64 gguid = *check.begin();
700 proposalRoles = queue.
roles;
702 if (!CheckQueueRoles(proposalRoles, proposalDungeons))
704 std::ostringstream o;
705 for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it)
708 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) single group roles not compatible%s", strGuids.c_str(), o.str().c_str());
714 uint8 minGroupSize = GetQueueMinGroupSize(proposalDungeons);
715 uint8 maxGroupSize = GetQueueMaxGroupSize(proposalDungeons);
716 if (numPlayers > maxGroupSize)
718 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) Too much players (%u)", strGuids.c_str(), numPlayers);
724 if (numPlayers < minGroupSize)
726 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) Compatibles but not enough players(%u)", strGuids.c_str(), numPlayers);
728 data.
roles = proposalRoles;
730 for (LfgGuidList::const_iterator itr = check.begin(); itr != check.end(); ++itr)
737 uint64 gguid = *check.begin();
741 if (!
sLFGMgr->AllQueued(check))
743 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) Group MATCH but can't create proposal!", strGuids.c_str());
755 for (LfgRolesMap::const_iterator itRoles = proposalRoles.begin(); itRoles != proposalRoles.end(); ++itRoles)
760 if (!leader || !proposal.
leader || std::rand() % 2)
761 proposal.
leader = itRoles->first;
764 else if (!leader && (!proposal.
leader || std::rand() % 2))
765 proposal.
leader = itRoles->first;
769 data.
role = itRoles->second;
770 data.
group = proposalGroups.find(itRoles->first)->second;
776 for (LfgGuidList::const_iterator itQueue = proposal.
queues.begin(); itQueue != proposal.
queues.end(); ++itQueue)
783 sLFGMgr->AddProposal(proposal);
785 SF_LOG_DEBUG(
"lfg.queue.match.compatibility.check",
"Guids: (%s) MATCH! Group formed", strGuids.c_str());
792 SF_LOG_TRACE(
"lfg.queue.timers.update",
"Updating queue timers...");
801 SF_LOG_DEBUG(
"lfg.queue.timers.update",
"Skipping queue data for [%u] with no selected dungeons",
GUID_LOPART(itQueue->first));
820 waitTime = SelectWaitTime(tanks, healers, dps, wtTank, wtHealer, wtDps, wtAvg);
823 CalculateRoleShortage(queueinfo.
roles, queueinfo.
dungeons, tanks, healers, dps);
824 waitTime = SelectWaitTime(tanks, healers, dps, wtTank, wtHealer, wtDps, wtAvg);
827 LfgQueueStatusData queueData(queueId, dungeonId, queueinfo.
joinTime, waitTime, wtAvg, wtTank, wtHealer, wtDps, queuedTime, tanks, healers, dps);
828 for (LfgRolesMap::const_iterator itPlayer = queueinfo.
roles.begin(); itPlayer != queueinfo.
roles.end(); ++itPlayer)
830 uint64 pguid = itPlayer->first;
838 LfgQueueDataContainer::const_iterator itr =
QueueDataStore.find(guid);
840 return itr->second.joinTime;
849 uint32 playersInGroup = 0;
850 uint32 currentEntries = 0;
852 uint32 storedOnlyEntries = 0;
858 time_t
const currTime = time(NULL);
860 for (
uint8 i = 0; i < 2; ++i)
864 newEntries =
uint32(queue.size());
866 currentEntries =
uint32(queue.size());
868 for (LfgGuidList::const_iterator it = queue.begin(); it != queue.end(); ++it)
874 playersInGroup +=
sLFGMgr->GetPlayerCount(guid);
886 for (LfgRolesMap::const_iterator itRoles = itr->second.roles.begin(); itRoles != itr->second.roles.end(); ++itRoles)
888 uint8 roles = itRoles->second;
897 if (!(roles & LFG_COMBAT_ROLE_MASK))
902 std::ostringstream o;
903 o <<
"Queued Players: " << players <<
" (in group: " << playersInGroup <<
") Groups: " << groups <<
"\n";
904 o <<
"Entries current/new/stored-only: " << currentEntries <<
"/" << newEntries <<
"/" << storedOnlyEntries <<
"\n";
905 o <<
"Role buckets tank/healer/damage/leader/none: " << tankRoles <<
"/" << healerRoles <<
"/" << damageRoles
906 <<
"/" << leaderRoles <<
"/" << noRoles <<
"\n";
919 <<
" roles: " << queueInfo.
roles.size()
927 o <<
" phase: current";
931 o <<
" phase: stored-only";
935 for (LfgRolesMap::const_iterator itRoles = queueInfo.
roles.begin(); itRoles != queueInfo.
roles.end(); ++itRoles)
936 o <<
" role " << itRoles->first <<
": " <<
GetRolesString(itRoles->second) <<
"\n";
944 std::ostringstream o;
959 CompatibleKeyContainsGuid(itr->first, itrQueue->first))
972 uint8 size = std::count(key.begin(), key.end(),
'|') + 1;
974 if (size <= storedSize)
977 SF_LOG_DEBUG(
"lfg.queue.compatibles.update",
"Changed (%s) to (%s) as best compatible group for " UI64FMTD,
DBCStorage< LFGDungeonEntry > sLFGDungeonStore(LFGDungeonEntryfmt)
MapDifficulty const * GetMapDifficultyData(uint32 mapId, DifficultyID difficulty)
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
#define SF_LOG_DEBUG(filterType__,...)
#define SF_LOG_ERROR(filterType__,...)
#define SF_LOG_TRACE(filterType__,...)
uint32 GUID_LOPART(uint64 x)
bool IS_GROUP_GUID(uint64 guid)
static bool CheckDpsOnlyRoles(LfgRolesMap &groles, uint8 neededDamage)
Assigns queued players to damage roles for role-neutral scenario queues.
static void SendLfgQueueStatus(uint64 guid, LfgQueueStatusData const &data)
Sends queue status to player.
static bool CheckGroupRoles(LfgRolesMap &groles)
Checks if given roles match, modifies given roles map with new roles.
static bool CheckFlexibleRaidRoles(LfgRolesMap &groles, uint8 maxPlayers)
Assigns queued players to their preferred combat role for flexible raid queues.
LfgCompatibility GetCompatibles(std::string const &key)
LfgQueueDataContainer QueueDataStore
Queued groups.
void RemoveFromQueue(uint64 guid)
LfgCompatibilityData * GetCompatibilityData(std::string const &key)
void UpdateBestCompatibleInQueue(LfgQueueDataContainer::iterator itrQueue, std::string const &key, LfgRolesMap const &roles)
void UpdateQueueTimers(uint8 queueId, time_t currTime)
LfgCompatibleContainer CompatibleMapStore
Compatible dungeons.
void AddToCurrentQueue(uint64 guid)
LfgGuidList currentQueueStore
Ordered list. Used to find groups.
void AddToQueue(uint64 guid, bool reQueue=false)
time_t GetJoinTime(uint64 guid) const
LfgWaitTimesContainer waitTimesTankStore
Average wait time to find a group queuing as tank.
std::string DumpQueueInfo(bool full=false) const
void UpdateWaitTimeAvg(int32 waitTime, uint32 dungeonId)
LfgWaitTimesContainer waitTimesAvgStore
Average wait time to find a group queuing as multiple roles.
void RemoveFromNewQueue(uint64 guid)
void FindBestCompatibleInQueue(LfgQueueDataContainer::iterator itrQueue)
std::string DumpCompatibleInfo(bool full=false) const
bool HasQueueData(uint64 guid) const
void SetCompatibles(std::string const &key, LfgCompatibility compatibles)
LfgGuidList newToQueueStore
New groups to add to queue.
void RemoveFromCurrentQueue(uint64 guid)
void UpdateWaitTimeHealer(int32 waitTime, uint32 dungeonId)
LfgCompatibility CheckCompatibility(LfgGuidList check)
void SetCompatibilityData(std::string const &key, LfgCompatibilityData const &compatibles)
LfgWaitTimesContainer waitTimesDpsStore
Average wait time to find a group queuing as dps.
void RemoveQueueData(uint64 guid)
void UpdateWaitTimeTank(int32 waitTime, uint32 dungeonId)
LfgWaitTimesContainer waitTimesHealerStore
Average wait time to find a group queuing as healer.
void UpdateWaitTimeDps(int32 waitTime, uint32 dungeonId)
void AddQueueData(uint64 guid, time_t joinTime, LfgDungeonSet const &dungeons, LfgRolesMap const &rolesMap)
void AddToNewQueue(uint64 guid)
void RemoveFromCompatibles(uint64 guid)
LfgCompatibility FindNewGroups(LfgGuidList &check, LfgGuidList &all)
C::value_type const & SelectRandomContainerElement(C const &container)
char const * GetCompatibleString(LfgCompatibility compatibles)
std::map< uint64, uint64 > LfgGroupsMap
@ LFG_COMPATIBLES_WITH_LESS_PLAYERS
@ LFG_INCOMPATIBLES_HAS_IGNORES
@ LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS
@ LFG_INCOMPATIBLES_NO_DUNGEONS
@ LFG_COMPATIBILITY_PENDING
@ LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS
@ LFG_INCOMPATIBLES_WRONG_GROUP_SIZE
@ LFG_INCOMPATIBLES_NO_ROLES
@ LFG_COMPATIBLES_BAD_STATES
std::set< uint32 > LfgDungeonSet
std::list< uint64 > LfgGuidList
std::string ConcatenateGuids(LfgGuidList const &guids)
std::map< uint64, uint8 > LfgRolesMap
std::string GetRolesString(uint8 roles)
std::set< uint64 > LfgGuidSet
std::string ConcatenateDungeons(LfgDungeonSet const &dungeons)
@ LFG_PROPOSAL_INITIATING
LfgCompatibility compatibility
Stores group data related to proposal to join.
uint32 dungeonId
Dungeon to join.
uint64 group
Proposal group (0 if new).
LfgGuidList queues
Queue Ids to remove/readd.
uint64 leader
Leader guid.
LfgProposalPlayerContainer players
Players data.
bool isNew
Determines if it's new group or not.
LfgProposalState state
State of the proposal.
time_t cancelTime
Time when we will cancel this proposal.
Stores player data related to proposal to join.
LfgAnswer accept
Accept status (-1 not answer | 0 Not agree | 1 agree).
uint64 group
Original group guid. 0 if no original group.
Stores player or group queue info.
LfgRolesMap roles
Selected Player Role/s.
time_t joinTime
Player queue join time (to calculate wait times).
std::string bestCompatible
Best compatible combination of people queued.
LfgDungeonSet dungeons
Selected Player/Group Dungeon/s.
uint8 healers
Healers needed.
uint32 number
Number of people used to get that wait time.