TrinityCore
Loading...
Searching...
No Matches
LFGQueue.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "LFGQueue.h"
19#include "Containers.h"
20#include "GameTime.h"
21#include "Group.h"
22#include "LFGMgr.h"
23#include "Log.h"
24#include <sstream>
25
26namespace lfg
27{
28
35std::string ConcatenateGuids(GuidList const& check)
36{
37 if (check.empty())
38 return "";
39
40 // need the guids in order to avoid duplicates
41 GuidSet guids(check.begin(), check.end());
42
43 std::ostringstream o;
44
45 GuidSet::const_iterator it = guids.begin();
46 o << it->ToHexString();
47 for (++it; it != guids.end(); ++it)
48 o << '|' << it->ToHexString();
49
50 return o.str();
51}
52
53char const* GetCompatibleString(LfgCompatibility compatibles)
54{
55 switch (compatibles)
56 {
58 return "Pending";
60 return "Compatibles (Bad States)";
62 return "Match";
64 return "Compatibles (Not enough players)";
66 return "Has ignores";
68 return "Multiple Lfg Groups";
70 return "Incompatible dungeons";
72 return "Incompatible roles";
74 return "Too many players";
76 return "Wrong group size";
77 default:
78 return "Unknown";
79 }
80}
81
82LfgQueueData::LfgQueueData() : joinTime(GameTime::GetGameTime()), tanks(LFG_TANKS_NEEDED),
84{ }
85
86LFGQueue::LFGQueue() = default;
87LFGQueue::LFGQueue(LFGQueue&& other) noexcept = default;
88LFGQueue& LFGQueue::operator=(LFGQueue&& right) noexcept = default;
89LFGQueue::~LFGQueue() = default;
90
91std::string LFGQueue::GetDetailedMatchRoles(GuidList const& check) const
92{
93 if (check.empty())
94 return "";
95
96 // need the guids in order to avoid duplicates
97 GuidSet guids(check.begin(), check.end());
98
99 std::ostringstream o;
100
101 GuidSet::const_iterator it = guids.begin();
102 o << it->ToString();
103 LfgQueueDataContainer::const_iterator itQueue = QueueDataStore.find(*it);
104 if (itQueue != QueueDataStore.end())
105 {
106 // skip leader flag, log only dps/tank/healer
107 auto role = itQueue->second.roles.find(*it);
108 if (role != itQueue->second.roles.end())
109 o << ' ' << GetRolesString(itQueue->second.roles.at(*it) & uint8(~PLAYER_ROLE_LEADER));
110 }
111
112 for (++it; it != guids.end(); ++it)
113 {
114 o << '|' << it->ToString();
115 itQueue = QueueDataStore.find(*it);
116 if (itQueue != QueueDataStore.end())
117 {
118 // skip leader flag, log only dps/tank/healer
119 auto role = itQueue->second.roles.find(*it);
120 if (role != itQueue->second.roles.end())
121 o << ' ' << GetRolesString(itQueue->second.roles.at(*it) & uint8(~PLAYER_ROLE_LEADER));
122 }
123 }
124
125 return o.str();
126}
127
128void LFGQueue::AddToQueue(ObjectGuid guid, bool reAdd)
129{
130 LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(guid);
131 if (itQueue == QueueDataStore.end())
132 {
133 TC_LOG_ERROR("lfg.queue.add", "Queue data not found for [{}]", guid.ToString());
134 return;
135 }
136
137 if (reAdd)
139 else
140 AddToNewQueue(guid);
141}
142
144{
145 RemoveFromNewQueue(guid);
148
149 std::string sguid = guid.ToHexString();
150
151 LfgQueueDataContainer::iterator itDelete = QueueDataStore.end();
152 for (LfgQueueDataContainer::iterator itr = QueueDataStore.begin(); itr != QueueDataStore.end(); ++itr)
153 if (itr->first != guid)
154 {
155 if (std::string::npos != itr->second.bestCompatible.find(sguid))
156 {
157 itr->second.bestCompatible.clear();
159 }
160 }
161 else
162 itDelete = itr;
163
164 if (itDelete != QueueDataStore.end())
165 QueueDataStore.erase(itDelete);
166}
167
169{
170 newToQueueStore.push_back(guid);
171}
172
174{
175 newToQueueStore.remove(guid);
176}
177
179{
180 currentQueueStore.push_back(guid);
181}
182
184{
185 currentQueueStore.push_front(guid);
186}
187
189{
190 currentQueueStore.remove(guid);
191}
192
193void LFGQueue::AddQueueData(ObjectGuid guid, time_t joinTime, LfgDungeonSet const& dungeons, LfgRolesMap const& rolesMap)
194{
195 QueueDataStore[guid] = LfgQueueData(joinTime, dungeons, rolesMap);
196 AddToQueue(guid);
197}
198
200{
201 LfgQueueDataContainer::iterator it = QueueDataStore.find(guid);
202 if (it != QueueDataStore.end())
203 QueueDataStore.erase(it);
204}
205
206void LFGQueue::UpdateWaitTimeAvg(int32 waitTime, uint32 dungeonId)
207{
208 LfgWaitTime &wt = waitTimesAvgStore[dungeonId];
209 uint32 old_number = wt.number++;
210 wt.time = int32((wt.time * old_number + waitTime) / wt.number);
211}
212
214{
215 LfgWaitTime &wt = waitTimesTankStore[dungeonId];
216 uint32 old_number = wt.number++;
217 wt.time = int32((wt.time * old_number + waitTime) / wt.number);
218}
219
221{
222 LfgWaitTime &wt = waitTimesHealerStore[dungeonId];
223 uint32 old_number = wt.number++;
224 wt.time = int32((wt.time * old_number + waitTime) / wt.number);
225}
226
227void LFGQueue::UpdateWaitTimeDps(int32 waitTime, uint32 dungeonId)
228{
229 LfgWaitTime &wt = waitTimesDpsStore[dungeonId];
230 uint32 old_number = wt.number++;
231 wt.time = int32((wt.time * old_number + waitTime) / wt.number);
232}
233
240{
241 std::string strGuid = guid.ToHexString();
242
243 TC_LOG_DEBUG("lfg.queue.data.compatibles.remove", "Removing {}", guid.ToString());
244 for (LfgCompatibleContainer::iterator itNext = CompatibleMapStore.begin(); itNext != CompatibleMapStore.end();)
245 {
246 LfgCompatibleContainer::iterator it = itNext++;
247 if (std::string::npos != it->first.find(strGuid))
248 CompatibleMapStore.erase(it);
249 }
250}
251
258void LFGQueue::SetCompatibles(std::string const& key, LfgCompatibility compatibles)
259{
261 data.compatibility = compatibles;
262}
263
264void LFGQueue::SetCompatibilityData(std::string const& key, LfgCompatibilityData const& data)
265{
266 CompatibleMapStore[key] = data;
267}
268
276{
277 LfgCompatibleContainer::iterator itr = CompatibleMapStore.find(key);
278 if (itr != CompatibleMapStore.end())
279 return itr->second.compatibility;
280
282}
283
285{
286 LfgCompatibleContainer::iterator itr = CompatibleMapStore.find(key);
287 if (itr != CompatibleMapStore.end())
288 return &(itr->second);
289
290 return nullptr;
291}
292
294{
295 uint8 proposals = 0;
296 GuidList firstNew;
297 while (!newToQueueStore.empty())
298 {
299 ObjectGuid frontguid = newToQueueStore.front();
300 TC_LOG_DEBUG("lfg.queue.match.check.new", "Checking [{}] newToQueue({}), currentQueue({})", frontguid.ToString(),
302
303 firstNew.clear();
304 firstNew.push_back(frontguid);
305 RemoveFromNewQueue(frontguid);
306
307 GuidList temporalList = currentQueueStore;
308 LfgCompatibility compatibles = FindNewGroups(firstNew, temporalList);
309
310 if (compatibles == LFG_COMPATIBLES_MATCH)
311 ++proposals;
312 else
313 AddToCurrentQueue(frontguid); // Lfg group not found, add this group to the queue.
314 }
315 return proposals;
316}
317
326{
327 std::string strGuids = ConcatenateGuids(check);
328 LfgCompatibility compatibles = GetCompatibles(strGuids);
329
330 TC_LOG_DEBUG("lfg.queue.match.check", "Guids: ({}): {} - all({})", GetDetailedMatchRoles(check), GetCompatibleString(compatibles), GetDetailedMatchRoles(all));
331 if (compatibles == LFG_COMPATIBILITY_PENDING) // Not previously cached, calculate
332 compatibles = CheckCompatibility(check);
333
334 if (compatibles == LFG_COMPATIBLES_BAD_STATES && sLFGMgr->AllQueued(check))
335 {
336 TC_LOG_DEBUG("lfg.queue.match.check", "Guids: ({}) compatibles (cached) changed from bad states to match", GetDetailedMatchRoles(check));
339 }
340
341 if (compatibles != LFG_COMPATIBLES_WITH_LESS_PLAYERS)
342 return compatibles;
343
344 // Try to match with queued groups
345 while (!all.empty())
346 {
347 check.push_back(all.front());
348 all.pop_front();
349 LfgCompatibility subcompatibility = FindNewGroups(check, all);
350 if (subcompatibility == LFG_COMPATIBLES_MATCH)
352 check.pop_back();
353 }
354 return compatibles;
355}
356
364{
365 std::string strGuids = ConcatenateGuids(check);
366 LfgProposal proposal;
367 LfgDungeonSet proposalDungeons;
368 LfgGroupsMap proposalGroups;
369 LfgRolesMap proposalRoles;
370
371 // Check for correct size
372 if (check.size() > MAX_GROUP_SIZE || check.empty())
373 {
374 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}): Size wrong - Not compatibles", GetDetailedMatchRoles(check));
376 }
377
378 // Check all-but-new compatiblitity
379 if (check.size() > 2)
380 {
381 ObjectGuid frontGuid = check.front();
382 check.pop_front();
383
384 // Check all-but-new compatibilities (New, A, B, C, D) --> check(A, B, C, D)
385 LfgCompatibility child_compatibles = CheckCompatibility(check);
386 if (child_compatibles < LFG_COMPATIBLES_WITH_LESS_PLAYERS) // Group not compatible
387 {
388 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}) child {} not compatibles", strGuids, GetDetailedMatchRoles(check));
389 SetCompatibles(strGuids, child_compatibles);
390 return child_compatibles;
391 }
392 check.push_front(frontGuid);
393 }
394
395 // Check if more than one LFG group and number of players joining
396 uint8 numPlayers = 0;
397 uint8 numLfgGroups = 0;
398 for (GuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAX_GROUP_SIZE; ++it)
399 {
400 ObjectGuid guid = *it;
401 LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(guid);
402 if (itQueue == QueueDataStore.end())
403 {
404 TC_LOG_ERROR("lfg.queue.match.compatibility.check", "Guid: [{}] is not queued but listed as queued!", guid.ToString());
405 RemoveFromQueue(guid);
407 }
408
409 // Store group so we don't need to call Mgr to get it later (if it's player group will be 0 otherwise would have joined as group)
410 for (LfgRolesMap::const_iterator it2 = itQueue->second.roles.begin(); it2 != itQueue->second.roles.end(); ++it2)
411 proposalGroups[it2->first] = itQueue->first.IsParty() ? itQueue->first : ObjectGuid::Empty;
412
413 numPlayers += itQueue->second.roles.size();
414
415 if (sLFGMgr->IsLfgGroup(guid))
416 {
417 if (!numLfgGroups)
418 proposal.group = guid;
419 ++numLfgGroups;
420 }
421 }
422
423 // Group with less that MAX_GROUP_SIZE members always compatible
424 if (check.size() == 1 && numPlayers != MAX_GROUP_SIZE)
425 {
426 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}) single group. Compatibles", GetDetailedMatchRoles(check));
427 LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(check.front());
428
430 data.roles = itQueue->second.roles;
432
433 UpdateBestCompatibleInQueue(itQueue, strGuids, data.roles);
434 SetCompatibilityData(strGuids, data);
436 }
437
438 if (numLfgGroups > 1)
439 {
440 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}) More than one Lfggroup ({})", GetDetailedMatchRoles(check), numLfgGroups);
443 }
444
445 if (numPlayers > MAX_GROUP_SIZE)
446 {
447 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}) Too many players ({})", GetDetailedMatchRoles(check), numPlayers);
450 }
451
452 // If it's single group no need to check for duplicate players, ignores, bad roles or bad dungeons as it's been checked before joining
453 if (check.size() > 1)
454 {
455 for (GuidList::const_iterator it = check.begin(); it != check.end(); ++it)
456 {
457 LfgRolesMap const& roles = QueueDataStore[(*it)].roles;
458 for (LfgRolesMap::const_iterator itRoles = roles.begin(); itRoles != roles.end(); ++itRoles)
459 {
460 LfgRolesMap::const_iterator itPlayer;
461 for (itPlayer = proposalRoles.begin(); itPlayer != proposalRoles.end(); ++itPlayer)
462 {
463 if (itRoles->first == itPlayer->first)
464 TC_LOG_ERROR("lfg.queue.match.compatibility.check", "Guids: ERROR! Player multiple times in queue! [{}]", itRoles->first.ToString());
465 else if (sLFGMgr->HasIgnore(itRoles->first, itPlayer->first))
466 break;
467 }
468 if (itPlayer == proposalRoles.end())
469 proposalRoles[itRoles->first] = itRoles->second;
470 }
471 }
472
473 if (uint8 playersize = numPlayers - proposalRoles.size())
474 {
475 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}) not compatible, {} players are ignoring each other", GetDetailedMatchRoles(check), playersize);
478 }
479
480 LfgRolesMap debugRoles = proposalRoles;
481 if (!LFGMgr::CheckGroupRoles(proposalRoles))
482 {
483 std::ostringstream o;
484 for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it)
485 o << ", " << it->first.ToHexString() << ": " << GetRolesString(it->second);
486
487 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}) Roles not compatible{}", GetDetailedMatchRoles(check), o.str());
490 }
491
492 GuidList::iterator itguid = check.begin();
493 proposalDungeons = QueueDataStore[*itguid].dungeons;
494 std::ostringstream o;
495 o << ", " << itguid->ToHexString() << ": (" << ConcatenateDungeons(proposalDungeons) << ")";
496 for (++itguid; itguid != check.end(); ++itguid)
497 {
498 LfgDungeonSet temporal;
499 LfgDungeonSet& dungeons = QueueDataStore[*itguid].dungeons;
500 o << ", " << itguid->ToHexString() << ": (" << ConcatenateDungeons(dungeons) << ")";
501 std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin()));
502 proposalDungeons = temporal;
503 }
504
505 if (proposalDungeons.empty())
506 {
507 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}) No compatible dungeons{}", GetDetailedMatchRoles(check), o.str());
510 }
511 }
512 else
513 {
514 ObjectGuid gguid = *check.begin();
515 LfgQueueData const& queue = QueueDataStore[gguid];
516 proposalDungeons = queue.dungeons;
517 proposalRoles = queue.roles;
518 LFGMgr::CheckGroupRoles(proposalRoles); // assing new roles
519 }
520
521 // Enough players?
522 if (numPlayers != MAX_GROUP_SIZE)
523 {
524 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}) Compatibles but not enough players({})", GetDetailedMatchRoles(check), numPlayers);
526 data.roles = proposalRoles;
527
528 for (GuidList::const_iterator itr = check.begin(); itr != check.end(); ++itr)
529 UpdateBestCompatibleInQueue(QueueDataStore.find(*itr), strGuids, data.roles);
530
531 SetCompatibilityData(strGuids, data);
533 }
534
535 ObjectGuid gguid = *check.begin();
536 proposal.queues = check;
537 proposal.isNew = numLfgGroups != 1 || sLFGMgr->GetOldState(gguid) != LFG_STATE_DUNGEON;
538
539 if (!sLFGMgr->AllQueued(check))
540 {
541 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}) Group MATCH but can't create proposal!", GetDetailedMatchRoles(check));
544 }
545
546 // Create a new proposal
549 proposal.leader.Clear();
551
552 bool leader = false;
553 for (LfgRolesMap::const_iterator itRoles = proposalRoles.begin(); itRoles != proposalRoles.end(); ++itRoles)
554 {
555 // Assing new leader
556 if (itRoles->second & PLAYER_ROLE_LEADER)
557 {
558 if (!leader || !proposal.leader || urand(0, 1))
559 proposal.leader = itRoles->first;
560 leader = true;
561 }
562 else if (!leader && (!proposal.leader || urand(0, 1)))
563 proposal.leader = itRoles->first;
564
565 // Assing player data and roles
566 LfgProposalPlayer &data = proposal.players[itRoles->first];
567 data.role = itRoles->second;
568 data.group = proposalGroups.find(itRoles->first)->second;
569 if (!proposal.isNew && !data.group.IsEmpty() && data.group == proposal.group) // Player from existing group, autoaccept
571 }
572
573 // Mark proposal members as not queued (but not remove queue data)
574 for (GuidList::const_iterator itQueue = proposal.queues.begin(); itQueue != proposal.queues.end(); ++itQueue)
575 {
576 ObjectGuid guid = (*itQueue);
577 RemoveFromNewQueue(guid);
579 }
580
581 sLFGMgr->AddProposal(proposal);
582
583 TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: ({}) MATCH! Group formed", GetDetailedMatchRoles(check));
586}
587
588void LFGQueue::UpdateQueueTimers(uint8 queueId, time_t currTime)
589{
590 TC_LOG_TRACE("lfg.queue.timers.update", "Updating queue timers...");
591 for (LfgQueueDataContainer::iterator itQueue = QueueDataStore.begin(); itQueue != QueueDataStore.end(); ++itQueue)
592 {
593 LfgQueueData& queueinfo = itQueue->second;
594 uint32 dungeonId = (*queueinfo.dungeons.begin());
595 uint32 queuedTime = uint32(currTime - queueinfo.joinTime);
596 uint8 role = PLAYER_ROLE_NONE;
597 int32 waitTime = -1;
598 int32 wtTank = waitTimesTankStore[dungeonId].time;
599 int32 wtHealer = waitTimesHealerStore[dungeonId].time;
600 int32 wtDps = waitTimesDpsStore[dungeonId].time;
601 int32 wtAvg = waitTimesAvgStore[dungeonId].time;
602
603 for (LfgRolesMap::const_iterator itPlayer = queueinfo.roles.begin(); itPlayer != queueinfo.roles.end(); ++itPlayer)
604 role |= itPlayer->second;
605 role &= ~PLAYER_ROLE_LEADER;
606
607 switch (role)
608 {
609 case PLAYER_ROLE_NONE: // Should not happen - just in case
610 waitTime = -1;
611 break;
612 case PLAYER_ROLE_TANK:
613 waitTime = wtTank;
614 break;
616 waitTime = wtHealer;
617 break;
619 waitTime = wtDps;
620 break;
621 default:
622 waitTime = wtAvg;
623 break;
624 }
625
626 if (queueinfo.bestCompatible.empty())
628
629 LfgQueueStatusData queueData(queueId, dungeonId, waitTime, wtAvg, wtTank, wtHealer, wtDps, queuedTime, queueinfo.tanks, queueinfo.healers, queueinfo.dps);
630 for (LfgRolesMap::const_iterator itPlayer = queueinfo.roles.begin(); itPlayer != queueinfo.roles.end(); ++itPlayer)
631 {
632 ObjectGuid pguid = itPlayer->first;
633 LFGMgr::SendLfgQueueStatus(pguid, queueData);
634 }
635 }
636}
637
639{
640 LfgQueueDataContainer::const_iterator itr = QueueDataStore.find(guid);
641 if (itr != QueueDataStore.end())
642 return itr->second.joinTime;
643
644 return 0;
645}
646
647std::string LFGQueue::DumpQueueInfo() const
648{
649 uint32 players = 0;
650 uint32 groups = 0;
651 uint32 playersInGroup = 0;
652
653 for (uint8 i = 0; i < 2; ++i)
654 {
655 GuidList const& queue = i ? newToQueueStore : currentQueueStore;
656 for (GuidList::const_iterator it = queue.begin(); it != queue.end(); ++it)
657 {
658 ObjectGuid guid = *it;
659 if (guid.IsParty())
660 {
661 groups++;
662 playersInGroup += sLFGMgr->GetPlayerCount(guid);
663 }
664 else
665 players++;
666 }
667 }
668 std::ostringstream o;
669 o << "Queued Players: " << players << " (in group: " << playersInGroup << ") Groups: " << groups << "\n";
670 return o.str();
671}
672
673std::string LFGQueue::DumpCompatibleInfo(bool full /* = false */) const
674{
675 std::ostringstream o;
676 o << "Compatible Map size: " << CompatibleMapStore.size() << "\n";
677 if (full)
678 for (LfgCompatibleContainer::const_iterator itr = CompatibleMapStore.begin(); itr != CompatibleMapStore.end(); ++itr)
679 {
680 o << "(" << itr->first << "): " << GetCompatibleString(itr->second.compatibility);
681 if (!itr->second.roles.empty())
682 {
683 o << " (";
684 bool first = true;
685 for (auto const& role : itr->second.roles)
686 {
687 if (!first)
688 o << "|";
689 o << role.first.ToString() << " " << GetRolesString(role.second & uint8(~PLAYER_ROLE_LEADER));
690 first = false;
691 }
692 o << ")";
693 }
694 o << "\n";
695 }
696
697 return o.str();
698}
699
700void LFGQueue::FindBestCompatibleInQueue(LfgQueueDataContainer::iterator itrQueue)
701{
702 TC_LOG_DEBUG("lfg.queue.compatibles.find", "{}", itrQueue->first.ToString());
703 std::string sguid = itrQueue->first.ToHexString();
704
705 for (LfgCompatibleContainer::const_iterator itr = CompatibleMapStore.begin(); itr != CompatibleMapStore.end(); ++itr)
706 if (itr->second.compatibility == LFG_COMPATIBLES_WITH_LESS_PLAYERS &&
707 std::string::npos != itr->first.find(sguid))
708 {
709 UpdateBestCompatibleInQueue(itrQueue, itr->first, itr->second.roles);
710 }
711}
712
713void LFGQueue::UpdateBestCompatibleInQueue(LfgQueueDataContainer::iterator itrQueue, std::string const& key, LfgRolesMap const& roles)
714{
715 LfgQueueData& queueData = itrQueue->second;
716
717 uint8 storedSize = queueData.bestCompatible.empty() ? 0 :
718 std::count(queueData.bestCompatible.begin(), queueData.bestCompatible.end(), '|') + 1;
719
720 uint8 size = std::count(key.begin(), key.end(), '|') + 1;
721
722 if (size <= storedSize)
723 return;
724
725 TC_LOG_DEBUG("lfg.queue.compatibles.update", "Changed ({}) to ({}) as best compatible group for {}",
726 queueData.bestCompatible, key, itrQueue->first.ToString());
727
728 queueData.bestCompatible = key;
729 queueData.tanks = LFG_TANKS_NEEDED;
730 queueData.healers = LFG_HEALERS_NEEDED;
731 queueData.dps = LFG_DPS_NEEDED;
732 for (LfgRolesMap::const_iterator it = roles.begin(); it != roles.end(); ++it)
733 {
734 uint8 role = it->second;
735 if (role & PLAYER_ROLE_TANK)
736 --queueData.tanks;
737 else if (role & PLAYER_ROLE_HEALER)
738 --queueData.healers;
739 else
740 --queueData.dps;
741 }
742}
743
744} // namespace lfg
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
#define MAX_GROUP_SIZE
Definition Group.h:50
#define sLFGMgr
Definition LFGMgr.h:515
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_TRACE(filterType__, message__,...)
Definition Log.h:178
std::list< ObjectGuid > GuidList
Definition ObjectGuid.h:433
std::set< ObjectGuid > GuidSet
Definition ObjectGuid.h:432
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
static ObjectGuid const Empty
Definition ObjectGuid.h:314
bool IsEmpty() const
Definition ObjectGuid.h:362
std::string ToHexString() const
std::string ToString() const
bool IsParty() const
Definition ObjectGuid.h:378
void Clear()
Definition ObjectGuid.h:329
static bool CheckGroupRoles(LfgRolesMap &groles)
Checks if given roles match, modifies given roles map with new roles.
Definition LFGMgr.cpp:878
static void SendLfgQueueStatus(ObjectGuid guid, LfgQueueStatusData const &data)
Sends queue status to player.
Definition LFGMgr.cpp:2037
void AddQueueData(ObjectGuid guid, time_t joinTime, LfgDungeonSet const &dungeons, LfgRolesMap const &rolesMap)
Definition LFGQueue.cpp:193
LfgCompatibility GetCompatibles(std::string const &key)
Definition LFGQueue.cpp:275
LfgQueueDataContainer QueueDataStore
Queued groups.
Definition LFGQueue.h:139
time_t GetJoinTime(ObjectGuid guid) const
Definition LFGQueue.cpp:638
LfgCompatibilityData * GetCompatibilityData(std::string const &key)
Definition LFGQueue.cpp:284
void UpdateBestCompatibleInQueue(LfgQueueDataContainer::iterator itrQueue, std::string const &key, LfgRolesMap const &roles)
Definition LFGQueue.cpp:713
LfgCompatibility FindNewGroups(GuidList &check, GuidList &all)
Definition LFGQueue.cpp:325
void RemoveQueueData(ObjectGuid guid)
Definition LFGQueue.cpp:199
LFGQueue & operator=(LFGQueue const &)=delete
void UpdateQueueTimers(uint8 queueId, time_t currTime)
Definition LFGQueue.cpp:588
LfgCompatibleContainer CompatibleMapStore
Compatible dungeons.
Definition LFGQueue.h:140
void AddToQueue(ObjectGuid guid, bool reAdd=false)
Definition LFGQueue.cpp:128
LfgWaitTimesContainer waitTimesTankStore
Average wait time to find a group queuing as tank.
Definition LFGQueue.h:143
void UpdateWaitTimeAvg(int32 waitTime, uint32 dungeonId)
Definition LFGQueue.cpp:206
LfgWaitTimesContainer waitTimesAvgStore
Average wait time to find a group queuing as multiple roles.
Definition LFGQueue.h:142
void RemoveFromQueue(ObjectGuid guid)
Definition LFGQueue.cpp:143
GuidList currentQueueStore
Ordered list. Used to find groups.
Definition LFGQueue.h:146
void RemoveFromNewQueue(ObjectGuid guid)
Definition LFGQueue.cpp:173
void FindBestCompatibleInQueue(LfgQueueDataContainer::iterator itrQueue)
Definition LFGQueue.cpp:700
std::string DumpCompatibleInfo(bool full=false) const
Definition LFGQueue.cpp:673
LfgCompatibility CheckCompatibility(GuidList check)
Definition LFGQueue.cpp:363
void SetCompatibles(std::string const &key, LfgCompatibility compatibles)
Definition LFGQueue.cpp:258
void AddToCurrentQueue(ObjectGuid guid)
Definition LFGQueue.cpp:178
void RemoveFromCompatibles(ObjectGuid guid)
Definition LFGQueue.cpp:239
uint8 FindGroups()
Definition LFGQueue.cpp:293
std::string DumpQueueInfo() const
Definition LFGQueue.cpp:647
void RemoveFromCurrentQueue(ObjectGuid guid)
Definition LFGQueue.cpp:188
void AddToNewQueue(ObjectGuid guid)
Definition LFGQueue.cpp:168
void UpdateWaitTimeHealer(int32 waitTime, uint32 dungeonId)
Definition LFGQueue.cpp:220
GuidList newToQueueStore
New groups to add to queue.
Definition LFGQueue.h:147
void SetCompatibilityData(std::string const &key, LfgCompatibilityData const &compatibles)
Definition LFGQueue.cpp:264
LfgWaitTimesContainer waitTimesDpsStore
Average wait time to find a group queuing as dps.
Definition LFGQueue.h:145
void UpdateWaitTimeTank(int32 waitTime, uint32 dungeonId)
Definition LFGQueue.cpp:213
LfgWaitTimesContainer waitTimesHealerStore
Average wait time to find a group queuing as healer.
Definition LFGQueue.h:144
std::string GetDetailedMatchRoles(GuidList const &check) const
Definition LFGQueue.cpp:91
void UpdateWaitTimeDps(int32 waitTime, uint32 dungeonId)
Definition LFGQueue.cpp:227
void AddToFrontCurrentQueue(ObjectGuid guid)
Definition LFGQueue.cpp:183
time_t GetGameTime()
Definition GameTime.cpp:52
auto SelectRandomContainerElement(C const &container) -> std::add_const_t< decltype(*std::ranges::begin(container))> &
Definition Containers.h:110
Definition LFG.cpp:24
@ LFG_HEALERS_NEEDED
Definition LFG.h:33
@ LFG_TANKS_NEEDED
Definition LFG.h:32
@ LFG_DPS_NEEDED
Definition LFG.h:34
char const * GetCompatibleString(LfgCompatibility compatibles)
Definition LFGQueue.cpp:53
std::map< ObjectGuid, uint8 > LfgRolesMap
Definition LFG.h:135
@ LFG_TIME_PROPOSAL
Definition LFGMgr.h:58
@ LFG_ANSWER_AGREE
Definition LFG.h:119
LfgCompatibility
Definition LFGQueue.h:28
@ LFG_COMPATIBLES_WITH_LESS_PLAYERS
Definition LFGQueue.h:36
@ LFG_INCOMPATIBLES_HAS_IGNORES
Definition LFGQueue.h:33
@ LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS
Definition LFGQueue.h:32
@ LFG_INCOMPATIBLES_NO_DUNGEONS
Definition LFGQueue.h:35
@ LFG_COMPATIBILITY_PENDING
Definition LFGQueue.h:29
@ LFG_COMPATIBLES_MATCH
Definition LFGQueue.h:38
@ LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS
Definition LFGQueue.h:31
@ LFG_INCOMPATIBLES_WRONG_GROUP_SIZE
Definition LFGQueue.h:30
@ LFG_INCOMPATIBLES_NO_ROLES
Definition LFGQueue.h:34
@ LFG_COMPATIBLES_BAD_STATES
Definition LFGQueue.h:37
std::string ConcatenateGuids(GuidList const &check)
Definition LFGQueue.cpp:35
std::string GetRolesString(uint8 roles)
Definition LFG.cpp:41
std::set< uint32 > LfgDungeonSet
Definition LFG.h:132
std::map< ObjectGuid, ObjectGuid > LfgGroupsMap
Definition LFG.h:136
std::string ConcatenateDungeons(LfgDungeonSet const &dungeons)
Definition LFG.cpp:26
@ PLAYER_ROLE_DAMAGE
Definition LFG.h:43
@ PLAYER_ROLE_TANK
Definition LFG.h:41
@ PLAYER_ROLE_NONE
Definition LFG.h:39
@ PLAYER_ROLE_LEADER
Definition LFG.h:40
@ PLAYER_ROLE_HEALER
Definition LFG.h:42
@ LFG_STATE_DUNGEON
Definition LFG.h:80
@ LFG_PROPOSAL_INITIATING
Definition LFGMgr.h:89
LfgCompatibility compatibility
Definition LFGQueue.h:48
Stores player data related to proposal to join.
Definition LFGMgr.h:248
ObjectGuid group
Accept status (-1 not answer | 0 Not agree | 1 agree)
Definition LFGMgr.h:252
LfgAnswer accept
Proposed role.
Definition LFGMgr.h:251
Stores group data related to proposal to join.
Definition LFGMgr.h:257
ObjectGuid leader
Proposal group (0 if new)
Definition LFGMgr.h:266
uint32 dungeonId
Proposal Id.
Definition LFGMgr.h:263
GuidList queues
Determines if it's new group or not.
Definition LFGMgr.h:270
LfgProposalPlayerContainer players
Show order in update window.
Definition LFGMgr.h:272
bool isNew
Dungeon Encounters.
Definition LFGMgr.h:269
LfgProposalState state
Dungeon to join.
Definition LFGMgr.h:264
ObjectGuid group
State of the proposal.
Definition LFGMgr.h:265
time_t cancelTime
Leader guid.
Definition LFGMgr.h:267
Stores player or group queue info.
Definition LFGQueue.h:54
LfgRolesMap roles
Selected Player Role/s.
Definition LFGQueue.h:67
time_t joinTime
Player queue join time (to calculate wait times)
Definition LFGQueue.h:62
std::string bestCompatible
Best compatible combination of people queued.
Definition LFGQueue.h:68
uint8 tanks
Tanks needed.
Definition LFGQueue.h:63
LfgDungeonSet dungeons
Selected Player/Group Dungeon/s.
Definition LFGQueue.h:66
uint8 healers
Healers needed.
Definition LFGQueue.h:64
uint8 dps
Dps needed.
Definition LFGQueue.h:65
int32 time
Wait time.
Definition LFGQueue.h:74
uint32 number
Number of people used to get that wait time.
Definition LFGQueue.h:75