TrinityCore
LFGMgr.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 "LFGMgr.h"
19#include "DatabaseEnv.h"
20#include "DB2Stores.h"
21#include "DisableMgr.h"
22#include "GameEventMgr.h"
23#include "GameTime.h"
24#include "Group.h"
25#include "GroupMgr.h"
26#include "InstanceLockMgr.h"
27#include "LFGGroupData.h"
28#include "LFGPlayerData.h"
29#include "LFGQueue.h"
30#include "Log.h"
31#include "Map.h"
32#include "ObjectAccessor.h"
33#include "ObjectMgr.h"
34#include "Player.h"
35#include "RBAC.h"
36#include "SharedDefines.h"
37#include "SocialMgr.h"
38#include "World.h"
39#include "WorldSession.h"
40#include <sstream>
41
42namespace lfg
43{
44
45LFGDungeonData::LFGDungeonData() : id(0), name(), map(0), type(0), expansion(0), group(0), contentTuningId(0),
46 difficulty(DIFFICULTY_NONE), seasonal(false), x(0.0f), y(0.0f), z(0.0f), o(0.0f), requiredItemLevel(0), finalDungeonEncounterId(0)
47{
48}
49
50LFGDungeonData::LFGDungeonData(LFGDungeonsEntry const* dbc) : id(dbc->ID), name(dbc->Name[sWorld->GetDefaultDbcLocale()]), map(dbc->MapID),
51 type(uint8(dbc->TypeID)), expansion(uint8(dbc->ExpansionLevel)), group(uint8(dbc->GroupID)),
52 contentTuningId(uint32(dbc->ContentTuningID)), difficulty(Difficulty(dbc->DifficultyID)),
53 seasonal((dbc->Flags[0] & LFG_FLAG_SEASONAL) != 0), x(0.0f), y(0.0f), z(0.0f), o(0.0f),
54 requiredItemLevel(0), finalDungeonEncounterId(0)
55{
56 if (JournalEncounterEntry const* journalEncounter = sJournalEncounterStore.LookupEntry(dbc->FinalEncounterID))
57 finalDungeonEncounterId = journalEncounter->DungeonEncounterID;
58}
59
60LFGMgr::LFGMgr() : m_QueueTimer(0), m_lfgProposalId(1),
61 m_options(sWorld->getIntConfig(CONFIG_LFG_OPTIONSMASK))
62{
63}
64
66{
67 for (LfgRewardContainer::iterator itr = RewardMapStore.begin(); itr != RewardMapStore.end(); ++itr)
68 delete itr->second;
69}
70
72{
73 if (!fields)
74 return;
75
76 if (!guid.IsParty())
77 return;
78
79 SetLeader(guid, ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt64()));
80
81 uint32 dungeon = fields[18].GetUInt32();
82 uint8 state = fields[19].GetUInt8();
83
84 if (!dungeon || !state)
85 return;
86
87 SetDungeon(guid, dungeon);
88
89 switch (state)
90 {
93 SetState(guid, (LfgState)state);
94 break;
95 default:
96 break;
97 }
98}
99
101{
102 if (!guid.IsParty())
103 return;
104
105 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
106
108 stmt->setUInt32(0, db_guid);
109 trans->Append(stmt);
110
111 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_LFG_DATA);
112 stmt->setUInt32(0, db_guid);
113 stmt->setUInt32(1, GetDungeon(guid));
114 stmt->setUInt32(2, GetState(guid));
115 trans->Append(stmt);
116
117 CharacterDatabase.CommitTransaction(trans);
118}
119
122{
123 uint32 oldMSTime = getMSTime();
124
125 for (LfgRewardContainer::iterator itr = RewardMapStore.begin(); itr != RewardMapStore.end(); ++itr)
126 delete itr->second;
127 RewardMapStore.clear();
128
129 // ORDER BY is very important for GetRandomDungeonReward!
130 QueryResult result = WorldDatabase.Query("SELECT dungeonId, maxLevel, firstQuestId, otherQuestId FROM lfg_dungeon_rewards ORDER BY dungeonId, maxLevel ASC");
131
132 if (!result)
133 {
134 TC_LOG_INFO("server.loading", ">> Loaded 0 lfg dungeon rewards. DB table `lfg_dungeon_rewards` is empty!");
135 return;
136 }
137
138 uint32 count = 0;
139
140 Field* fields = nullptr;
141 do
142 {
143 fields = result->Fetch();
144 uint32 dungeonId = fields[0].GetUInt32();
145 uint32 maxLevel = fields[1].GetUInt8();
146 uint32 firstQuestId = fields[2].GetUInt32();
147 uint32 otherQuestId = fields[3].GetUInt32();
148
149 if (!GetLFGDungeonEntry(dungeonId))
150 {
151 TC_LOG_ERROR("sql.sql", "Dungeon {} specified in table `lfg_dungeon_rewards` does not exist!", dungeonId);
152 continue;
153 }
154
155 if (!maxLevel || maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
156 {
157 TC_LOG_ERROR("sql.sql", "Level {} specified for dungeon {} in table `lfg_dungeon_rewards` can never be reached!", maxLevel, dungeonId);
158 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
159 }
160
161 if (!firstQuestId || !sObjectMgr->GetQuestTemplate(firstQuestId))
162 {
163 TC_LOG_ERROR("sql.sql", "First quest {} specified for dungeon {} in table `lfg_dungeon_rewards` does not exist!", firstQuestId, dungeonId);
164 continue;
165 }
166
167 if (otherQuestId && !sObjectMgr->GetQuestTemplate(otherQuestId))
168 {
169 TC_LOG_ERROR("sql.sql", "Other quest {} specified for dungeon {} in table `lfg_dungeon_rewards` does not exist!", otherQuestId, dungeonId);
170 otherQuestId = 0;
171 }
172
173 RewardMapStore.insert(LfgRewardContainer::value_type(dungeonId, new LfgReward(maxLevel, firstQuestId, otherQuestId)));
174 ++count;
175 }
176 while (result->NextRow());
177
178 TC_LOG_INFO("server.loading", ">> Loaded {} lfg dungeon rewards in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
179}
180
182{
183 LFGDungeonContainer::const_iterator itr = LfgDungeonStore.find(id);
184 if (itr != LfgDungeonStore.end())
185 return &(itr->second);
186
187 return nullptr;
188}
189
190void LFGMgr::LoadLFGDungeons(bool reload /* = false */)
191{
192 uint32 oldMSTime = getMSTime();
193
194 LfgDungeonStore.clear();
195
196 // Initialize Dungeon map with data from dbcs
197 for (uint32 i = 0; i < sLFGDungeonsStore.GetNumRows(); ++i)
198 {
199 LFGDungeonsEntry const* dungeon = sLFGDungeonsStore.LookupEntry(i);
200 if (!dungeon)
201 continue;
202
203 if (!sDB2Manager.GetMapDifficultyData(dungeon->MapID, Difficulty(dungeon->DifficultyID)))
204 continue;
205
206 switch (dungeon->TypeID)
207 {
208 case LFG_TYPE_DUNGEON:
209 case LFG_TYPE_HEROIC:
210 case LFG_TYPE_RAID:
211 case LFG_TYPE_RANDOM:
212 LfgDungeonStore[dungeon->ID] = LFGDungeonData(dungeon);
213 break;
214 }
215 }
216
217 // Fill teleport locations from DB
218 QueryResult result = WorldDatabase.Query("SELECT dungeonId, position_x, position_y, position_z, orientation, requiredItemLevel FROM lfg_dungeon_template");
219 if (!result)
220 {
221 TC_LOG_INFO("server.loading", ">> Loaded 0 lfg dungeon templates. DB table `lfg_dungeon_template` is empty!");
222 return;
223 }
224
225 uint32 count = 0;
226
227 do
228 {
229 Field* fields = result->Fetch();
230 uint32 dungeonId = fields[0].GetUInt32();
231 LFGDungeonContainer::iterator dungeonItr = LfgDungeonStore.find(dungeonId);
232 if (dungeonItr == LfgDungeonStore.end())
233 {
234 TC_LOG_ERROR("sql.sql", "table `lfg_entrances` contains coordinates for wrong dungeon {}", dungeonId);
235 continue;
236 }
237
238 LFGDungeonData& data = dungeonItr->second;
239 data.x = fields[1].GetFloat();
240 data.y = fields[2].GetFloat();
241 data.z = fields[3].GetFloat();
242 data.o = fields[4].GetFloat();
243 data.requiredItemLevel = fields[5].GetUInt16();
244
245 ++count;
246 }
247 while (result->NextRow());
248
249 TC_LOG_INFO("server.loading", ">> Loaded {} lfg dungeon templates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
250
251 // Fill all other teleport coords from areatriggers
252 for (LFGDungeonContainer::iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr)
253 {
254 LFGDungeonData& dungeon = itr->second;
255
256 // No teleport coords in database, load from areatriggers
257 if (dungeon.type != LFG_TYPE_RANDOM && dungeon.x == 0.0f && dungeon.y == 0.0f && dungeon.z == 0.0f)
258 {
259 AreaTriggerStruct const* at = sObjectMgr->GetMapEntranceTrigger(dungeon.map);
260 if (!at)
261 {
262 TC_LOG_ERROR("sql.sql", "Failed to load dungeon {} (Id: {}), cant find areatrigger for map {}", dungeon.name, dungeon.id, dungeon.map);
263 continue;
264 }
265
266 dungeon.map = at->target_mapId;
267 dungeon.x = at->target_X;
268 dungeon.y = at->target_Y;
269 dungeon.z = at->target_Z;
270 dungeon.o = at->target_Orientation;
271 }
272
273 if (dungeon.type != LFG_TYPE_RANDOM)
274 CachedDungeonMapStore[dungeon.group].insert(dungeon.id);
275 CachedDungeonMapStore[0].insert(dungeon.id);
276 }
277
278 if (reload)
279 CachedDungeonMapStore.clear();
280}
281
283{
284 static LFGMgr instance;
285 return &instance;
286}
287
289{
291 return;
292
293 time_t currTime = GameTime::GetGameTime();
294
295 // Remove obsolete role checks
296 for (LfgRoleCheckContainer::iterator it = RoleChecksStore.begin(); it != RoleChecksStore.end();)
297 {
298 LfgRoleCheckContainer::iterator itRoleCheck = it++;
299 LfgRoleCheck& roleCheck = itRoleCheck->second;
300 if (currTime < roleCheck.cancelTime)
301 continue;
303
304 for (LfgRolesMap::const_iterator itRoles = roleCheck.roles.begin(); itRoles != roleCheck.roles.end(); ++itRoles)
305 {
306 ObjectGuid guid = itRoles->first;
307 RestoreState(guid, "Remove Obsolete RoleCheck");
308 SendLfgRoleCheckUpdate(guid, roleCheck);
309 if (guid == roleCheck.leader)
311 }
312
313 RestoreState(itRoleCheck->first, "Remove Obsolete RoleCheck");
314 RoleChecksStore.erase(itRoleCheck);
315 }
316
317 // Remove obsolete proposals
318 for (LfgProposalContainer::iterator it = ProposalsStore.begin(); it != ProposalsStore.end();)
319 {
320 LfgProposalContainer::iterator itRemove = it++;
321 if (itRemove->second.cancelTime < currTime)
323 }
324
325 // Remove obsolete kicks
326 for (LfgPlayerBootContainer::iterator it = BootsStore.begin(); it != BootsStore.end();)
327 {
328 LfgPlayerBootContainer::iterator itBoot = it++;
329 LfgPlayerBoot& boot = itBoot->second;
330 if (boot.cancelTime < currTime)
331 {
332 boot.inProgress = false;
333 for (LfgAnswerContainer::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
334 {
335 ObjectGuid pguid = itVotes->first;
336 if (pguid != boot.victim)
337 SendLfgBootProposalUpdate(pguid, boot);
338 }
339 SetVoteKick(itBoot->first, false);
340 BootsStore.erase(itBoot);
341 }
342 }
343
344 uint32 lastProposalId = m_lfgProposalId;
345 // Check if a proposal can be formed with the new groups being added
346 for (LfgQueueContainer::iterator it = QueuesStore.begin(); it != QueuesStore.end(); ++it)
347 if (uint8 newProposals = it->second.FindGroups())
348 TC_LOG_DEBUG("lfg.update", "Found {} new groups in queue {}", newProposals, it->first);
349
350 if (lastProposalId != m_lfgProposalId)
351 {
352 // FIXME lastProposalId ? lastProposalId +1 ?
353 for (LfgProposalContainer::const_iterator itProposal = ProposalsStore.find(m_lfgProposalId); itProposal != ProposalsStore.end(); ++itProposal)
354 {
355 uint32 proposalId = itProposal->first;
356 LfgProposal& proposal = ProposalsStore[proposalId];
357
358 ObjectGuid guid;
359 for (LfgProposalPlayerContainer::const_iterator itPlayers = proposal.players.begin(); itPlayers != proposal.players.end(); ++itPlayers)
360 {
361 guid = itPlayers->first;
363 ObjectGuid gguid = GetGroup(guid);
364 if (!gguid.IsEmpty())
365 {
368 }
369 else
371 SendLfgUpdateProposal(guid, proposal);
372 }
373
374 if (proposal.state == LFG_PROPOSAL_SUCCESS)
375 UpdateProposal(proposalId, guid, true);
376 }
377 }
378
379 // Update all players status queue info
381 {
382 m_QueueTimer = 0;
383 for (LfgQueueContainer::iterator it = QueuesStore.begin(); it != QueuesStore.end(); ++it)
384 it->second.UpdateQueueTimers(it->first, currTime);
385 }
386 else
387 m_QueueTimer += diff;
388}
389
399void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons)
400{
401 if (!player || !player->GetSession() || dungeons.empty())
402 return;
403
404 // Sanitize input roles
405 roles &= PLAYER_ROLE_ANY;
406 roles = FilterClassRoles(player, roles);
407
408 // At least 1 role must be selected
410 return;
411
412 Group* grp = player->GetGroup();
413 ObjectGuid guid = player->GetGUID();
414 ObjectGuid gguid = grp ? grp->GetGUID() : guid;
415 LfgJoinResultData joinData;
416 GuidSet players;
417 uint32 rDungeonId = 0;
418 bool isContinue = grp && grp->isLFGGroup() && GetState(gguid) != LFG_STATE_FINISHED_DUNGEON;
419
420 // Do not allow to change dungeon in the middle of a current dungeon
421 if (isContinue)
422 {
423 dungeons.clear();
424 dungeons.insert(GetDungeon(gguid));
425 }
426
427 // Already in queue?
428 LfgState state = GetState(gguid);
429 if (state == LFG_STATE_QUEUED)
430 {
431 LFGQueue& queue = GetQueue(gguid);
432 queue.RemoveFromQueue(gguid);
433 }
434
435 // Check player or group member restrictions
437 joinData.result = LFG_JOIN_NO_SLOTS;
438 else if (player->InBattleground() || player->InArena() || player->InBattlegroundQueue())
440 else if (player->HasAura(LFG_SPELL_DUNGEON_DESERTER))
442 else if (!isContinue && player->HasAura(LFG_SPELL_DUNGEON_COOLDOWN))
444 else if (dungeons.empty())
445 joinData.result = LFG_JOIN_NO_SLOTS;
446 else if (player->HasAura(9454)) // check Freeze debuff
447 joinData.result = LFG_JOIN_NO_SLOTS;
448 else if (grp)
449 {
450 if (grp->GetMembersCount() > MAX_GROUP_SIZE)
452 else
453 {
454 uint8 memberCount = 0;
455 for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr && joinData.result == LFG_JOIN_OK; itr = itr->next())
456 {
457 if (Player* plrg = itr->GetSource())
458 {
459 if (!plrg->GetSession()->HasPermission(rbac::RBAC_PERM_JOIN_DUNGEON_FINDER))
461 if (plrg->HasAura(LFG_SPELL_DUNGEON_DESERTER))
463 else if (!isContinue && plrg->HasAura(LFG_SPELL_DUNGEON_COOLDOWN))
465 else if (plrg->InBattleground() || plrg->InArena() || plrg->InBattlegroundQueue())
467 else if (plrg->HasAura(9454)) // check Freeze debuff
468 {
469 joinData.result = LFG_JOIN_NO_SLOTS;
470 joinData.playersMissingRequirement.push_back(&plrg->GetName());
471 }
472 ++memberCount;
473 players.insert(plrg->GetGUID());
474 }
475 }
476
477 if (joinData.result == LFG_JOIN_OK && memberCount != grp->GetMembersCount())
479 }
480 }
481 else
482 players.insert(player->GetGUID());
483
484 // Check if all dungeons are valid
485 bool isRaid = false;
486 if (joinData.result == LFG_JOIN_OK)
487 {
488 bool isDungeon = false;
489 for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end() && joinData.result == LFG_JOIN_OK; ++it)
490 {
491 LfgType type = GetDungeonType(*it);
492 switch (type)
493 {
494 case LFG_TYPE_RANDOM:
495 if (dungeons.size() > 1) // Only allow 1 random dungeon
496 joinData.result = LFG_JOIN_INVALID_SLOT;
497 else
498 rDungeonId = (*dungeons.begin());
499 [[fallthrough]]; // Random can only be dungeon or heroic dungeon
500 case LFG_TYPE_HEROIC:
501 case LFG_TYPE_DUNGEON:
502 if (isRaid)
504 isDungeon = true;
505 break;
506 case LFG_TYPE_RAID:
507 if (isDungeon)
509 isRaid = true;
510 break;
511 default:
512 joinData.result = LFG_JOIN_INVALID_SLOT;
513 break;
514 }
515 }
516
517 // it could be changed
518 if (joinData.result == LFG_JOIN_OK)
519 {
520 // Expand random dungeons and check restrictions
521 if (rDungeonId)
522 dungeons = GetDungeonsByRandom(rDungeonId);
523
524 // if we have lockmap then there are no compatible dungeons
525 GetCompatibleDungeons(&dungeons, players, &joinData.lockmap, &joinData.playersMissingRequirement, isContinue);
526 if (dungeons.empty())
527 joinData.result = LFG_JOIN_NO_SLOTS;
528 }
529 }
530
531 // Can't join. Send result
532 if (joinData.result != LFG_JOIN_OK)
533 {
534 TC_LOG_DEBUG("lfg.join", "{} joining with {} members. Result: {}, Dungeons: {}",
535 guid.ToString(), grp ? grp->GetMembersCount() : 1, joinData.result, ConcatenateDungeons(dungeons));
536
537 if (!dungeons.empty()) // Only should show lockmap when have no dungeons available
538 joinData.lockmap.clear();
539 player->GetSession()->SendLfgJoinResult(joinData);
540 return;
541 }
542
543 if (isRaid)
544 {
545 TC_LOG_DEBUG("lfg.join", "{} trying to join raid browser and it's disabled.", guid.ToString());
546 return;
547 }
548
550 ticket.RequesterGuid = guid;
551 ticket.Id = GetQueueId(gguid);
553 ticket.Time = int32(GameTime::GetGameTime());
554 std::string debugNames = "";
555 if (grp) // Begin rolecheck
556 {
557 // Create new rolecheck
558 LfgRoleCheck& roleCheck = RoleChecksStore[gguid];
561 roleCheck.leader = guid;
562 roleCheck.dungeons = dungeons;
563 roleCheck.rDungeonId = rDungeonId;
564
565 if (rDungeonId)
566 {
567 dungeons.clear();
568 dungeons.insert(rDungeonId);
569 }
570
572 // Send update to player
574 for (GroupReference* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
575 {
576 if (Player* plrg = itr->GetSource())
577 {
578 ObjectGuid pguid = plrg->GetGUID();
579 plrg->GetSession()->SendLfgUpdateStatus(updateData, true);
581 SetTicket(pguid, ticket);
582 if (!isContinue)
583 SetSelectedDungeons(pguid, dungeons);
584 roleCheck.roles[pguid] = 0;
585 if (!debugNames.empty())
586 debugNames.append(", ");
587 debugNames.append(plrg->GetName());
588 }
589 }
590 // Update leader role
591 UpdateRoleCheck(gguid, guid, roles);
592 }
593 else // Add player to queue
594 {
595 LfgRolesMap rolesMap;
596 rolesMap[guid] = roles;
597 LFGQueue& queue = GetQueue(guid);
598 queue.AddQueueData(guid, GameTime::GetGameTime(), dungeons, rolesMap);
599
600 if (!isContinue)
601 {
602 if (rDungeonId)
603 {
604 dungeons.clear();
605 dungeons.insert(rDungeonId);
606 }
607 SetSelectedDungeons(guid, dungeons);
608 }
609 // Send update to player
610 SetTicket(guid, ticket);
611 SetRoles(guid, roles);
615 player->GetSession()->SendLfgJoinResult(joinData);
616 debugNames.append(player->GetName());
617 }
618
619 TC_LOG_DEBUG("lfg.join", "{} joined ({}), Members: {}. Dungeons ({}): {}", guid.ToString(),
620 grp ? "group" : "player", debugNames, uint32(dungeons.size()), ConcatenateDungeons(dungeons));
621}
622
629void LFGMgr::LeaveLfg(ObjectGuid guid, bool disconnected)
630{
631 ObjectGuid gguid = guid.IsParty() ? guid : GetGroup(guid);
632
633 TC_LOG_DEBUG("lfg.leave", "{} left ({})", guid.ToString(), guid == gguid ? "group" : "player");
634
635 LfgState state = GetState(guid);
636 switch (state)
637 {
638 case LFG_STATE_QUEUED:
639 if (!gguid.IsEmpty())
640 {
641 LfgState newState = LFG_STATE_NONE;
642 LfgState oldState = GetOldState(gguid);
643
644 // Set the new state to LFG_STATE_DUNGEON/LFG_STATE_FINISHED_DUNGEON if the group is already in a dungeon
645 // This is required in case a LFG group vote-kicks a player in a dungeon, queues, then leaves the queue (maybe to queue later again)
646 if (Group* group = sGroupMgr->GetGroupByGUID(gguid))
647 if (group->isLFGGroup() && GetDungeon(gguid) && (oldState == LFG_STATE_DUNGEON || oldState == LFG_STATE_FINISHED_DUNGEON))
648 newState = oldState;
649
650 LFGQueue& queue = GetQueue(gguid);
651 queue.RemoveFromQueue(gguid);
652 SetState(gguid, newState);
653 GuidSet const& players = GetPlayers(gguid);
654 for (GuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
655 {
656 SetState(*it, newState);
658 }
659 }
660 else
661 {
662 LFGQueue& queue = GetQueue(guid);
663 queue.RemoveFromQueue(guid);
666 }
667 break;
669 if (!gguid.IsEmpty())
670 UpdateRoleCheck(gguid); // No player to update role = LFG_ROLECHECK_ABORTED
671 break;
673 {
674 // Remove from Proposals
675 LfgProposalContainer::iterator it = ProposalsStore.begin();
676 ObjectGuid pguid = gguid == guid ? GetLeader(gguid) : guid;
677 while (it != ProposalsStore.end())
678 {
679 LfgProposalPlayerContainer::iterator itPlayer = it->second.players.find(pguid);
680 if (itPlayer != it->second.players.end())
681 {
682 // Mark the player/leader of group who left as didn't accept the proposal
683 itPlayer->second.accept = LFG_ANSWER_DENY;
684 break;
685 }
686 ++it;
687 }
688
689 // Remove from queue - if proposal is found, RemoveProposal will call RemoveFromQueue
690 if (it != ProposalsStore.end())
692 break;
693 }
694 case LFG_STATE_NONE:
696 break;
699 if (guid != gguid && !disconnected) // Player
701 break;
702 }
703}
704
706{
707 auto itr = PlayersStore.find(guid);
708 if (itr != PlayersStore.end())
709 return &itr->second.GetTicket();
710
711 return nullptr;
712}
713
721void LFGMgr::UpdateRoleCheck(ObjectGuid gguid, ObjectGuid guid /* = ObjectGuid::Empty */, uint8 roles /* = PLAYER_ROLE_NONE */)
722{
723 if (!gguid)
724 return;
725
726 LfgRolesMap check_roles;
727 LfgRoleCheckContainer::iterator itRoleCheck = RoleChecksStore.find(gguid);
728 if (itRoleCheck == RoleChecksStore.end())
729 return;
730
731 // Sanitize input roles
732 roles &= PLAYER_ROLE_ANY;
733
734 if (!guid.IsEmpty())
735 {
736 if (Player* player = ObjectAccessor::FindPlayer(guid))
737 roles = FilterClassRoles(player, roles);
738 else
739 return;
740 }
741
742 LfgRoleCheck& roleCheck = itRoleCheck->second;
743 bool sendRoleChosen = roleCheck.state != LFG_ROLECHECK_DEFAULT && !guid.IsEmpty();
744
745 if (!guid)
746 roleCheck.state = LFG_ROLECHECK_ABORTED;
747 else if (roles < PLAYER_ROLE_TANK) // Player selected no role.
748 roleCheck.state = LFG_ROLECHECK_NO_ROLE;
749 else
750 {
751 roleCheck.roles[guid] = roles;
752
753 // Check if all players have selected a role
754 LfgRolesMap::const_iterator itRoles = roleCheck.roles.begin();
755 while (itRoles != roleCheck.roles.end() && itRoles->second != PLAYER_ROLE_NONE)
756 ++itRoles;
757
758 if (itRoles == roleCheck.roles.end())
759 {
760 // use temporal var to check roles, CheckGroupRoles modifies the roles
761 check_roles = roleCheck.roles;
763 }
764 }
765
766 LfgDungeonSet dungeons;
767 if (roleCheck.rDungeonId)
768 dungeons.insert(roleCheck.rDungeonId);
769 else
770 dungeons = roleCheck.dungeons;
771
773 for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it)
774 {
775 ObjectGuid pguid = it->first;
776
777 if (sendRoleChosen)
778 SendLfgRoleChosen(pguid, guid, roles);
779
780 SendLfgRoleCheckUpdate(pguid, roleCheck);
781 switch (roleCheck.state)
782 {
784 continue;
787 SetRoles(pguid, it->second);
789 break;
790 default:
791 if (roleCheck.leader == pguid)
792 SendLfgJoinResult(pguid, joinData);
794 RestoreState(pguid, "Rolecheck Failed");
795 break;
796 }
797 }
798
799 if (roleCheck.state == LFG_ROLECHECK_FINISHED)
800 {
802 LFGQueue& queue = GetQueue(gguid);
803 queue.AddQueueData(gguid, time_t(GameTime::GetGameTime()), roleCheck.dungeons, roleCheck.roles);
804 RoleChecksStore.erase(itRoleCheck);
805 }
806 else if (roleCheck.state != LFG_ROLECHECK_INITIALITING)
807 {
808 RestoreState(gguid, "Rolecheck Failed");
809 RoleChecksStore.erase(itRoleCheck);
810 }
811}
812
820void LFGMgr::GetCompatibleDungeons(LfgDungeonSet* dungeons, GuidSet const& players, LfgLockPartyMap* lockMap, std::vector<std::string const*>* playersMissingRequirement, bool isContinue)
821{
822 lockMap->clear();
823
824 std::map<uint32, uint32> lockedDungeons;
825 std::unordered_set<uint32> dungeonsToRemove;
826
827 for (GuidSet::const_iterator it = players.begin(); it != players.end() && !dungeons->empty(); ++it)
828 {
829 ObjectGuid guid = (*it);
830 LfgLockMap cachedLockMap = GetLockedDungeons(guid);
832 for (LfgLockMap::const_iterator it2 = cachedLockMap.begin(); it2 != cachedLockMap.end() && !dungeons->empty(); ++it2)
833 {
834 uint32 dungeonId = (it2->first & 0x00FFFFFF); // Compare dungeon ids
835 LfgDungeonSet::iterator itDungeon = dungeons->find(dungeonId);
836 if (itDungeon != dungeons->end())
837 {
838 bool eraseDungeon = true;
839
840 // Don't remove the dungeon if team members are trying to continue a locked instance
841 if (it2->second.lockStatus == LFG_LOCKSTATUS_RAID_LOCKED && isContinue)
842 {
843 LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId);
844 ASSERT(dungeon);
845 ASSERT(player);
846 MapDb2Entries entries{ dungeon->map, Difficulty(dungeon->difficulty) };
847 if (InstanceLock* playerBind = sInstanceLockMgr.FindActiveInstanceLock(guid, entries))
848 {
849 uint32 dungeonInstanceId = playerBind->GetInstanceId();
850 auto itLockedDungeon = lockedDungeons.find(dungeonId);
851 if (itLockedDungeon == lockedDungeons.end() || itLockedDungeon->second == dungeonInstanceId)
852 eraseDungeon = false;
853
854 lockedDungeons[dungeonId] = dungeonInstanceId;
855 }
856 }
857
858 if (eraseDungeon)
859 dungeonsToRemove.insert(dungeonId);
860
861 (*lockMap)[guid][dungeonId] = it2->second;
862 playersMissingRequirement->push_back(&player->GetName());
863 }
864 }
865 }
866
867 for (uint32 dungeonIdToRemove : dungeonsToRemove)
868 dungeons->erase(dungeonIdToRemove);
869
870 if (!dungeons->empty())
871 lockMap->clear();
872}
873
881{
882 if (groles.empty())
883 return false;
884
885 uint8 damage = 0;
886 uint8 tank = 0;
887 uint8 healer = 0;
888
889 for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it)
890 {
891 uint8 role = it->second & ~PLAYER_ROLE_LEADER;
892 if (role == PLAYER_ROLE_NONE)
893 return false;
894
895 if (role & PLAYER_ROLE_DAMAGE)
896 {
897 if (role != PLAYER_ROLE_DAMAGE)
898 {
899 it->second -= PLAYER_ROLE_DAMAGE;
900 if (CheckGroupRoles(groles))
901 return true;
902 it->second += PLAYER_ROLE_DAMAGE;
903 }
904 else if (damage == LFG_DPS_NEEDED)
905 return false;
906 else
907 damage++;
908 }
909
910 if (role & PLAYER_ROLE_HEALER)
911 {
912 if (role != PLAYER_ROLE_HEALER)
913 {
914 it->second -= PLAYER_ROLE_HEALER;
915 if (CheckGroupRoles(groles))
916 return true;
917 it->second += PLAYER_ROLE_HEALER;
918 }
919 else if (healer == LFG_HEALERS_NEEDED)
920 return false;
921 else
922 healer++;
923 }
924
925 if (role & PLAYER_ROLE_TANK)
926 {
927 if (role != PLAYER_ROLE_TANK)
928 {
929 it->second -= PLAYER_ROLE_TANK;
930 if (CheckGroupRoles(groles))
931 return true;
932 it->second += PLAYER_ROLE_TANK;
933 }
934 else if (tank == LFG_TANKS_NEEDED)
935 return false;
936 else
937 tank++;
938 }
939 }
940 return (tank + healer + damage) == uint8(groles.size());
941}
942
948{
949 GuidList players, tankPlayers, healPlayers, dpsPlayers;
950 GuidList playersToTeleport;
951
952 for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
953 {
954 ObjectGuid guid = it->first;
955 if (guid == proposal.leader)
956 players.push_back(guid);
957 else
958 switch (it->second.role & ~PLAYER_ROLE_LEADER)
959 {
960 case PLAYER_ROLE_TANK:
961 tankPlayers.push_back(guid);
962 break;
964 healPlayers.push_back(guid);
965 break;
967 dpsPlayers.push_back(guid);
968 break;
969 default:
970 ABORT_MSG("Invalid LFG role %u", it->second.role);
971 break;
972 }
973
974 if (proposal.isNew || GetGroup(guid) != proposal.group)
975 playersToTeleport.push_back(guid);
976 }
977
978 players.splice(players.end(), tankPlayers);
979 players.splice(players.end(), healPlayers);
980 players.splice(players.end(), dpsPlayers);
981
982 // Set the dungeon difficulty
983 LFGDungeonData const* dungeon = GetLFGDungeon(proposal.dungeonId);
984 ASSERT(dungeon);
985
986 Group* grp = !proposal.group.IsEmpty() ? sGroupMgr->GetGroupByGUID(proposal.group) : nullptr;
987 for (GuidList::const_iterator it = players.begin(); it != players.end(); ++it)
988 {
989 ObjectGuid pguid = (*it);
991 if (!player)
992 continue;
993
994 Group* group = player->GetGroup();
995 if (group && group != grp)
996 group->RemoveMember(player->GetGUID());
997
998 if (!grp)
999 {
1000 grp = new Group();
1001 grp->ConvertToLFG();
1002 grp->Create(player);
1003 ObjectGuid gguid = grp->GetGUID();
1005 sGroupMgr->AddGroup(grp);
1006 }
1007 else if (group != grp)
1008 grp->AddMember(player);
1009
1010 grp->SetLfgRoles(pguid, proposal.players.find(pguid)->second.role);
1011
1012 // Add the cooldown spell if queued for a random dungeon
1013 LfgDungeonSet const& dungeons = GetSelectedDungeons(player->GetGUID());
1014 if (!dungeons.empty())
1015 {
1016 uint32 rDungeonId = (*dungeons.begin());
1017 LFGDungeonData const* dungeonEntry = GetLFGDungeon(rDungeonId);
1018 if (dungeonEntry && dungeonEntry->type == LFG_TYPE_RANDOM)
1019 player->CastSpell(player, LFG_SPELL_DUNGEON_COOLDOWN, false);
1020 }
1021 }
1022
1023 ASSERT(grp);
1025 ObjectGuid gguid = grp->GetGUID();
1026 SetDungeon(gguid, dungeon->Entry());
1028
1029 _SaveToDB(gguid, grp->GetDbStoreId());
1030
1031 // Teleport Player
1032 for (GuidList::const_iterator it = playersToTeleport.begin(); it != playersToTeleport.end(); ++it)
1033 if (Player* player = ObjectAccessor::FindPlayer(*it))
1034 TeleportPlayer(player, false);
1035
1036 // Update group info
1037 grp->SendUpdate();
1038}
1039
1041{
1042 proposal.id = ++m_lfgProposalId;
1043 ProposalsStore[m_lfgProposalId] = proposal;
1044 return m_lfgProposalId;
1045}
1046
1054void LFGMgr::UpdateProposal(uint32 proposalId, ObjectGuid guid, bool accept)
1055{
1056 // Check if the proposal exists
1057 LfgProposalContainer::iterator itProposal = ProposalsStore.find(proposalId);
1058 if (itProposal == ProposalsStore.end())
1059 return;
1060
1061 LfgProposal& proposal = itProposal->second;
1062
1063 // Check if proposal have the current player
1064 LfgProposalPlayerContainer::iterator itProposalPlayer = proposal.players.find(guid);
1065 if (itProposalPlayer == proposal.players.end())
1066 return;
1067
1068 LfgProposalPlayer& player = itProposalPlayer->second;
1069 player.accept = LfgAnswer(accept);
1070
1071 TC_LOG_DEBUG("lfg.proposal.update", "{}, Proposal {}, Selection: {}", guid.ToString(), proposalId, accept);
1072 if (!accept)
1073 {
1075 return;
1076 }
1077
1078 // check if all have answered and reorder players (leader first)
1079 bool allAnswered = true;
1080 for (LfgProposalPlayerContainer::const_iterator itPlayers = proposal.players.begin(); itPlayers != proposal.players.end(); ++itPlayers)
1081 if (itPlayers->second.accept != LFG_ANSWER_AGREE) // No answer (-1) or not accepted (0)
1082 allAnswered = false;
1083
1084 if (!allAnswered)
1085 {
1086 for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
1087 SendLfgUpdateProposal(it->first, proposal);
1088
1089 return;
1090 }
1091
1092 bool sendUpdate = proposal.state != LFG_PROPOSAL_SUCCESS;
1093 proposal.state = LFG_PROPOSAL_SUCCESS;
1094 time_t joinTime = GameTime::GetGameTime();
1095
1096 LFGQueue& queue = GetQueue(guid);
1098 for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
1099 {
1100 ObjectGuid pguid = it->first;
1101 ObjectGuid gguid = it->second.group;
1102 uint32 dungeonId = (*GetSelectedDungeons(pguid).begin());
1103 int32 waitTime = -1;
1104 if (sendUpdate)
1105 SendLfgUpdateProposal(pguid, proposal);
1106
1107 if (!gguid.IsEmpty())
1108 {
1109 waitTime = int32((joinTime - queue.GetJoinTime(gguid)) / IN_MILLISECONDS);
1110 SendLfgUpdateStatus(pguid, updateData, false);
1111 }
1112 else
1113 {
1114 waitTime = int32((joinTime - queue.GetJoinTime(pguid)) / IN_MILLISECONDS);
1115 SendLfgUpdateStatus(pguid, updateData, false);
1116 }
1118 SendLfgUpdateStatus(pguid, updateData, true);
1119 SendLfgUpdateStatus(pguid, updateData, false);
1120
1121 // Update timers
1122 uint8 role = GetRoles(pguid);
1123 role &= ~PLAYER_ROLE_LEADER;
1124 switch (role)
1125 {
1126 case PLAYER_ROLE_DAMAGE:
1127 queue.UpdateWaitTimeDps(waitTime, dungeonId);
1128 break;
1129 case PLAYER_ROLE_HEALER:
1130 queue.UpdateWaitTimeHealer(waitTime, dungeonId);
1131 break;
1132 case PLAYER_ROLE_TANK:
1133 queue.UpdateWaitTimeTank(waitTime, dungeonId);
1134 break;
1135 default:
1136 queue.UpdateWaitTimeAvg(waitTime, dungeonId);
1137 break;
1138 }
1139
1140 // Store the number of players that were present in group when joining RFD, used for achievement purposes
1141 if (Player* player = ObjectAccessor::FindConnectedPlayer(pguid))
1142 if (Group* group = player->GetGroup())
1143 PlayersStore[pguid].SetNumberOfPartyMembersAtJoin(group->GetMembersCount());
1144
1146 }
1147
1148 // Remove players/groups from Queue
1149 for (GuidList::const_iterator it = proposal.queues.begin(); it != proposal.queues.end(); ++it)
1150 queue.RemoveFromQueue(*it);
1151
1152 MakeNewGroup(proposal);
1153 ProposalsStore.erase(itProposal);
1154}
1155
1162void LFGMgr::RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdateType type)
1163{
1164 LfgProposal& proposal = itProposal->second;
1165 proposal.state = LFG_PROPOSAL_FAILED;
1166
1167 TC_LOG_DEBUG("lfg.proposal.remove", "Proposal {}, state FAILED, UpdateType {}", itProposal->first, type);
1168 // Mark all people that didn't answered as no accept
1170 for (LfgProposalPlayerContainer::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
1171 if (it->second.accept == LFG_ANSWER_PENDING)
1172 it->second.accept = LFG_ANSWER_DENY;
1173
1174 // Mark players/groups to be removed
1175 GuidSet toRemove;
1176 for (LfgProposalPlayerContainer::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
1177 {
1178 if (it->second.accept == LFG_ANSWER_AGREE)
1179 continue;
1180
1181 ObjectGuid guid = !it->second.group.IsEmpty() ? it->second.group : it->first;
1182 // Player didn't accept or still pending when no secs left
1183 if (it->second.accept == LFG_ANSWER_DENY || type == LFG_UPDATETYPE_PROPOSAL_FAILED)
1184 {
1185 it->second.accept = LFG_ANSWER_DENY;
1186 toRemove.insert(guid);
1187 }
1188 }
1189
1190 // Notify players
1191 for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
1192 {
1193 ObjectGuid guid = it->first;
1194 ObjectGuid gguid = !it->second.group.IsEmpty() ? it->second.group : guid;
1195
1196 SendLfgUpdateProposal(guid, proposal);
1197
1198 if (toRemove.find(gguid) != toRemove.end()) // Didn't accept or in same group that someone that didn't accept
1199 {
1200 LfgUpdateData updateData;
1201 if (it->second.accept == LFG_ANSWER_DENY)
1202 {
1203 updateData.updateType = type;
1204 TC_LOG_DEBUG("lfg.proposal.remove", "{} didn't accept. Removing from queue and compatible cache", guid.ToString());
1205 }
1206 else
1207 {
1209 TC_LOG_DEBUG("lfg.proposal.remove", "{} in same group that someone that didn't accept. Removing from queue and compatible cache", guid.ToString());
1210 }
1211
1212 RestoreState(guid, "Proposal Fail (didn't accepted or in group with someone that didn't accept");
1213 if (gguid != guid)
1214 {
1215 RestoreState(it->second.group, "Proposal Fail (someone in group didn't accepted)");
1216 SendLfgUpdateStatus(guid, updateData, true);
1217 }
1218 else
1219 SendLfgUpdateStatus(guid, updateData, false);
1220 }
1221 else
1222 {
1223 TC_LOG_DEBUG("lfg.proposal.remove", "Readding {} to queue.", guid.ToString());
1225 if (gguid != guid)
1226 {
1227 SetState(gguid, LFG_STATE_QUEUED);
1229 }
1230 else
1232 }
1233 }
1234
1235 LFGQueue& queue = GetQueue(proposal.players.begin()->first);
1236 // Remove players/groups from queue
1237 for (GuidSet::const_iterator it = toRemove.begin(); it != toRemove.end(); ++it)
1238 {
1239 ObjectGuid guid = *it;
1240 queue.RemoveFromQueue(guid);
1241 proposal.queues.remove(guid);
1242 }
1243
1244 // Readd to queue
1245 for (GuidList::const_iterator it = proposal.queues.begin(); it != proposal.queues.end(); ++it)
1246 {
1247 ObjectGuid guid = *it;
1248 queue.AddToQueue(guid, true);
1249 }
1250
1251 ProposalsStore.erase(itProposal);
1252}
1253
1262void LFGMgr::InitBoot(ObjectGuid gguid, ObjectGuid kicker, ObjectGuid victim, std::string const& reason)
1263{
1264 SetVoteKick(gguid, true);
1265
1266 LfgPlayerBoot& boot = BootsStore[gguid];
1267 boot.inProgress = true;
1269 boot.reason = reason;
1270 boot.victim = victim;
1271
1272 GuidSet const& players = GetPlayers(gguid);
1273
1274 // Set votes
1275 for (GuidSet::const_iterator itr = players.begin(); itr != players.end(); ++itr)
1276 {
1277 ObjectGuid guid = (*itr);
1278 boot.votes[guid] = LFG_ANSWER_PENDING;
1279 }
1280
1281 boot.votes[victim] = LFG_ANSWER_DENY; // Victim auto vote NO
1282 boot.votes[kicker] = LFG_ANSWER_AGREE; // Kicker auto vote YES
1283
1284 // Notify players
1285 for (GuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
1286 SendLfgBootProposalUpdate(*it, boot);
1287}
1288
1295void LFGMgr::UpdateBoot(ObjectGuid guid, bool accept)
1296{
1297 ObjectGuid gguid = GetGroup(guid);
1298 if (!gguid)
1299 return;
1300
1301 LfgPlayerBootContainer::iterator itBoot = BootsStore.find(gguid);
1302 if (itBoot == BootsStore.end())
1303 return;
1304
1305 LfgPlayerBoot& boot = itBoot->second;
1306
1307 if (boot.votes[guid] != LFG_ANSWER_PENDING) // Cheat check: Player can't vote twice
1308 return;
1309
1310 boot.votes[guid] = LfgAnswer(accept);
1311
1312 uint8 agreeNum = 0;
1313 uint8 denyNum = 0;
1314 for (LfgAnswerContainer::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
1315 {
1316 switch (itVotes->second)
1317 {
1318 case LFG_ANSWER_PENDING:
1319 break;
1320 case LFG_ANSWER_AGREE:
1321 ++agreeNum;
1322 break;
1323 case LFG_ANSWER_DENY:
1324 ++denyNum;
1325 break;
1326 }
1327 }
1328
1329 // if we don't have enough votes (agree or deny) do nothing
1330 if (agreeNum < LFG_GROUP_KICK_VOTES_NEEDED && (boot.votes.size() - denyNum) >= LFG_GROUP_KICK_VOTES_NEEDED)
1331 return;
1332
1333 // Send update info to all players
1334 boot.inProgress = false;
1335 for (LfgAnswerContainer::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
1336 {
1337 ObjectGuid pguid = itVotes->first;
1338 if (pguid != boot.victim)
1339 SendLfgBootProposalUpdate(pguid, boot);
1340 }
1341
1342 SetVoteKick(gguid, false);
1343 if (agreeNum == LFG_GROUP_KICK_VOTES_NEEDED) // Vote passed - Kick player
1344 {
1345 if (Group* group = sGroupMgr->GetGroupByGUID(gguid))
1347 DecreaseKicksLeft(gguid);
1348 }
1349 BootsStore.erase(itBoot);
1350}
1351
1359void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*/)
1360{
1361 LFGDungeonData const* dungeon = nullptr;
1362 Group* group = player->GetGroup();
1363
1364 if (group && group->isLFGGroup())
1365 dungeon = GetLFGDungeon(GetDungeon(group->GetGUID()));
1366
1367 if (!dungeon)
1368 {
1369 TC_LOG_DEBUG("lfg.teleport", "Player {} not in group/lfggroup or dungeon not found!",
1370 player->GetName());
1372 return;
1373 }
1374
1375 if (out)
1376 {
1377 TC_LOG_DEBUG("lfg.teleport", "Player {} is being teleported out. Current Map {} - Expected Map {}",
1378 player->GetName(), player->GetMapId(), uint32(dungeon->map));
1379 if (player->GetMapId() == uint32(dungeon->map))
1380 player->TeleportToBGEntryPoint();
1381
1382 return;
1383 }
1384
1386
1387 if (!player->IsAlive())
1389 else if (player->IsFalling() || player->HasUnitState(UNIT_STATE_JUMPING))
1391 else if (player->IsMirrorTimerActive(FATIGUE_TIMER))
1393 else if (player->GetVehicle())
1395 else if (!player->GetCharmedGUID().IsEmpty())
1397 else if (player->HasAura(9454)) // check Freeze debuff
1399 else if (player->GetMapId() != uint32(dungeon->map)) // Do not teleport players in dungeon to the entrance
1400 {
1401 uint32 mapid = dungeon->map;
1402 float x = dungeon->x;
1403 float y = dungeon->y;
1404 float z = dungeon->z;
1405 float orientation = dungeon->o;
1406
1407 if (!fromOpcode)
1408 {
1409 // Select a player inside to be teleported to
1410 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
1411 {
1412 Player* plrg = itr->GetSource();
1413 if (plrg && plrg != player && plrg->GetMapId() == uint32(dungeon->map))
1414 {
1415 mapid = plrg->GetMapId();
1416 x = plrg->GetPositionX();
1417 y = plrg->GetPositionY();
1418 z = plrg->GetPositionZ();
1419 orientation = plrg->GetOrientation();
1420 break;
1421 }
1422 }
1423 }
1424
1425 if (!player->GetMap()->IsDungeon())
1426 player->SetBattlegroundEntryPoint();
1427
1428 player->FinishTaxiFlight();
1429
1430 if (!player->TeleportTo(mapid, x, y, z, orientation))
1432 }
1433 else
1435
1436 if (error != LFG_TELEPORT_RESULT_NONE)
1437 player->GetSession()->SendLfgTeleportError(error);
1438
1439 TC_LOG_DEBUG("lfg.teleport", "Player {} is being teleported in to map {} "
1440 "(x: {}, y: {}, z: {}) Result: {}", player->GetName(), dungeon->map,
1441 dungeon->x, dungeon->y, dungeon->z, error);
1442}
1443
1451void LFGMgr::OnDungeonEncounterDone(ObjectGuid gguid, std::array<uint32, 4> const& dungeonEncounterIds, Map const* currMap)
1452{
1453 if (GetState(gguid) == LFG_STATE_FINISHED_DUNGEON) // Shouldn't happen. Do not reward multiple times
1454 {
1455 TC_LOG_DEBUG("lfg.dungeon.finish", "Group: {} already rewarded", gguid.ToString());
1456 return;
1457 }
1458
1459 uint32 gDungeonId = GetDungeon(gguid);
1460 LFGDungeonData const* dungeonDone = GetLFGDungeon(gDungeonId);
1461 // LFGDungeons can point to a DungeonEncounter from any difficulty so we need this kind of lenient check
1462 if (std::find(dungeonEncounterIds.begin(), dungeonEncounterIds.end(), dungeonDone->finalDungeonEncounterId) == dungeonEncounterIds.end())
1463 return;
1464
1465 FinishDungeon(gguid, gDungeonId, currMap);
1466}
1467
1474void LFGMgr::FinishDungeon(ObjectGuid gguid, const uint32 dungeonId, Map const* currMap)
1475{
1476 uint32 gDungeonId = GetDungeon(gguid);
1477 if (gDungeonId != dungeonId)
1478 {
1479 TC_LOG_DEBUG("lfg.dungeon.finish", "Group {} finished dungeon {} but queued for {}", gguid.ToString(), dungeonId, gDungeonId);
1480 return;
1481 }
1482
1483 if (GetState(gguid) == LFG_STATE_FINISHED_DUNGEON) // Shouldn't happen. Do not reward multiple times
1484 {
1485 TC_LOG_DEBUG("lfg.dungeon.finish", "Group: {} already rewarded", gguid.ToString());
1486 return;
1487 }
1488
1490
1491 GuidSet const& players = GetPlayers(gguid);
1492 for (GuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
1493 {
1494 ObjectGuid guid = (*it);
1496 {
1497 TC_LOG_DEBUG("lfg.dungeon.finish", "Group: {}, Player: {} already rewarded", gguid.ToString(), guid.ToString());
1498 continue;
1499 }
1500
1501 uint32 rDungeonId = 0;
1502 LfgDungeonSet const& dungeons = GetSelectedDungeons(guid);
1503 if (!dungeons.empty())
1504 rDungeonId = (*dungeons.begin());
1505
1507
1508 // Give rewards only if its a random dungeon
1509 LFGDungeonData const* dungeon = GetLFGDungeon(rDungeonId);
1510
1511 if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM && !dungeon->seasonal))
1512 {
1513 TC_LOG_DEBUG("lfg.dungeon.finish", "Group: {}, Player: {} dungeon {} is not random or seasonal", gguid.ToString(), guid.ToString(), rDungeonId);
1514 continue;
1515 }
1516
1517 Player* player = ObjectAccessor::FindPlayer(guid);
1518 if (!player)
1519 {
1520 TC_LOG_DEBUG("lfg.dungeon.finish", "Group: {}, Player: {} not found in world", gguid.ToString(), guid.ToString());
1521 continue;
1522 }
1523
1524 if (player->FindMap() != currMap)
1525 {
1526 TC_LOG_DEBUG("lfg.dungeon.finish", "Group: {}, Player: {} is in a different map", gguid.ToString(), guid.ToString());
1527 continue;
1528 }
1529
1531
1532 LFGDungeonData const* dungeonDone = GetLFGDungeon(dungeonId);
1533 uint32 mapId = dungeonDone ? uint32(dungeonDone->map) : 0;
1534
1535 if (player->GetMapId() != mapId)
1536 {
1537 TC_LOG_DEBUG("lfg.dungeon.finish", "Group: {}, Player: {} is in map {} and should be in {} to get reward", gguid.ToString(), guid.ToString(), player->GetMapId(), mapId);
1538 continue;
1539 }
1540
1541 // Update achievements
1542 if (dungeon->difficulty == DIFFICULTY_HEROIC)
1543 {
1544 uint8 lfdRandomPlayers = 0;
1545 if (uint8 numParty = PlayersStore[guid].GetNumberOfPartyMembersAtJoin())
1546 lfdRandomPlayers = 5 - numParty;
1547 else
1548 lfdRandomPlayers = 4;
1550 }
1551
1552 LfgReward const* reward = GetRandomDungeonReward(rDungeonId, player->GetLevel());
1553 if (!reward)
1554 continue;
1555
1556 bool done = false;
1557 Quest const* quest = sObjectMgr->GetQuestTemplate(reward->firstQuest);
1558 if (!quest)
1559 continue;
1560
1561 // if we can take the quest, means that we haven't done this kind of "run", IE: First Heroic Random of Day.
1562 if (player->CanRewardQuest(quest, false))
1563 player->RewardQuest(quest, LootItemType::Item, 0, nullptr, false);
1564 else
1565 {
1566 done = true;
1567 quest = sObjectMgr->GetQuestTemplate(reward->otherQuest);
1568 if (!quest)
1569 continue;
1570 // we give reward without informing client (retail does this)
1571 player->RewardQuest(quest, LootItemType::Item, 0, nullptr, false);
1572 }
1573
1574 // Give rewards
1575 TC_LOG_DEBUG("lfg.dungeon.finish", "Group: {}, Player: {} done dungeon {}, {} previously done.", gguid.ToString(), guid.ToString(), GetDungeon(gguid), done ? " " : " not");
1576 LfgPlayerRewardData data = LfgPlayerRewardData(dungeon->Entry(), GetDungeon(gguid, false), done, quest);
1577 player->GetSession()->SendLfgPlayerReward(data);
1578 }
1579}
1580
1581// --------------------------------------------------------------------------//
1582// Auxiliar Functions
1583// --------------------------------------------------------------------------//
1584
1592{
1593 LFGDungeonData const* dungeon = GetLFGDungeon(randomdungeon);
1594 uint32 group = dungeon ? dungeon->group : 0;
1595 return CachedDungeonMapStore[group];
1596}
1597
1606{
1607 LfgReward const* rew = nullptr;
1608 LfgRewardContainerBounds bounds = RewardMapStore.equal_range(dungeon & 0x00FFFFFF);
1609 for (LfgRewardContainer::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
1610 {
1611 rew = itr->second;
1612 // ordered properly at loading
1613 if (itr->second->maxLevel >= level)
1614 break;
1615 }
1616
1617 return rew;
1618}
1619
1627{
1628 LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId);
1629 if (!dungeon)
1630 return LFG_TYPE_NONE;
1631
1632 return LfgType(dungeon->type);
1633}
1634
1636{
1637 LfgState state;
1638 if (guid.IsParty())
1639 {
1640 state = GroupsStore[guid].GetState();
1641 TC_LOG_TRACE("lfg.data.group.state.get", "Group: {}, State: {}", guid.ToString(), GetStateString(state));
1642 }
1643 else
1644 {
1645 state = PlayersStore[guid].GetState();
1646 TC_LOG_TRACE("lfg.data.player.state.get", "Player: {}, State: {}", guid.ToString(), GetStateString(state));
1647 }
1648
1649 return state;
1650}
1651
1653{
1654 LfgState state;
1655 if (guid.IsParty())
1656 {
1657 state = GroupsStore[guid].GetOldState();
1658 TC_LOG_TRACE("lfg.data.group.oldstate.get", "Group: {}, Old state: {}", guid.ToString(), state);
1659 }
1660 else
1661 {
1662 state = PlayersStore[guid].GetOldState();
1663 TC_LOG_TRACE("lfg.data.player.oldstate.get", "Player: {}, Old state: {}", guid.ToString(), state);
1664 }
1665
1666 return state;
1667}
1668
1670{
1671 ASSERT(gguid.IsParty());
1672
1673 bool active = GroupsStore[gguid].IsVoteKickActive();
1674 TC_LOG_TRACE("lfg.data.group.votekick.get", "Group: {}, Active: {}", gguid.ToString(), active);
1675
1676 return active;
1677}
1678
1679uint32 LFGMgr::GetDungeon(ObjectGuid guid, bool asId /*= true */)
1680{
1681 uint32 dungeon = GroupsStore[guid].GetDungeon(asId);
1682 TC_LOG_TRACE("lfg.data.group.dungeon.get", "Group: {}, asId: {}, Dungeon: {}", guid.ToString(), asId, dungeon);
1683 return dungeon;
1684}
1685
1687{
1688 uint32 dungeonId = GroupsStore[guid].GetDungeon(true);
1689 uint32 mapId = 0;
1690 if (dungeonId)
1691 if (LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId))
1692 mapId = dungeon->map;
1693
1694 TC_LOG_TRACE("lfg.data.group.dungeon.map", "Group: {}, MapId: {} (DungeonId: {})", guid.ToString(), mapId, dungeonId);
1695
1696 return mapId;
1697}
1698
1700{
1701 uint8 roles = PlayersStore[guid].GetRoles();
1702 TC_LOG_TRACE("lfg.data.player.role.get", "Player: {}, Role: {}", guid.ToString(), roles);
1703 return roles;
1704}
1705
1707{
1708 TC_LOG_TRACE("lfg.data.player.dungeons.selected.get", "Player: {}, Selected Dungeons: {}", guid.ToString(), ConcatenateDungeons(PlayersStore[guid].GetSelectedDungeons()));
1709 return PlayersStore[guid].GetSelectedDungeons();
1710}
1711
1713{
1714 if (GetState(guid) != LFG_STATE_NONE)
1715 {
1716 LfgDungeonSet const& dungeons = GetSelectedDungeons(guid);
1717 if (!dungeons.empty())
1718 {
1719 LFGDungeonData const* dungeon = GetLFGDungeon(*dungeons.begin());
1720 if (dungeon && dungeon->type == LFG_TYPE_RANDOM)
1721 return *dungeons.begin();
1722 }
1723 }
1724
1725 return 0;
1726}
1727
1729{
1730 TC_LOG_TRACE("lfg.data.player.dungeons.locked.get", "Player: {}, LockedDungeons.", guid.ToString());
1731 LfgLockMap lock;
1733 if (!player)
1734 {
1735 TC_LOG_WARN("lfg.data.player.dungeons.locked.get", "Player: {} not ingame while retrieving his LockedDungeons.", guid.ToString());
1736 return lock;
1737 }
1738
1739 uint8 level = player->GetLevel();
1740 uint8 expansion = player->GetSession()->GetExpansion();
1741 LfgDungeonSet const& dungeons = GetDungeonsByRandom(0);
1743
1744 for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it)
1745 {
1746 LFGDungeonData const* dungeon = GetLFGDungeon(*it);
1747 if (!dungeon) // should never happen - We provide a list from sLfgDungeonsStore
1748 continue;
1749
1750 uint32 lockStatus = [&]() -> uint32
1751 {
1752 if (denyJoin)
1754 if (dungeon->expansion > expansion)
1756 if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player))
1758 if (DisableMgr::IsDisabledFor(DISABLE_TYPE_LFG_MAP, dungeon->map, player))
1760 if (sInstanceLockMgr.FindActiveInstanceLock(guid, { dungeon->map, Difficulty(dungeon->difficulty) }))
1762 if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(dungeon->contentTuningId, player->m_playerData->CtrOptions->ContentTuningConditionMask))
1763 {
1764 if (levels->MinLevel > level)
1766 if (levels->MaxLevel < level)
1768 }
1769 if (dungeon->seasonal && !IsSeasonActive(dungeon->id))
1771 if (dungeon->requiredItemLevel > player->GetAverageItemLevel())
1773 if (AccessRequirement const* ar = sObjectMgr->GetAccessRequirement(dungeon->map, Difficulty(dungeon->difficulty)))
1774 {
1775 if (ar->achievement && !player->HasAchieved(ar->achievement))
1777 if (player->GetTeam() == ALLIANCE && ar->quest_A && !player->GetQuestRewardStatus(ar->quest_A))
1779 if (player->GetTeam() == HORDE && ar->quest_H && !player->GetQuestRewardStatus(ar->quest_H))
1781
1782 if (ar->item)
1783 {
1784 if (!player->HasItemCount(ar->item) && (!ar->item2 || !player->HasItemCount(ar->item2)))
1786 }
1787 else if (ar->item2 && !player->HasItemCount(ar->item2))
1789 }
1790
1791 /* @todo VoA closed if WG is not under team control (LFG_LOCKSTATUS_RAID_LOCKED)
1792 lockData = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE;
1793 lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL;
1794 lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL;
1795 */
1796 return 0;
1797 }();
1798
1799 if (lockStatus)
1800 lock[dungeon->Entry()] = LfgLockInfoData(lockStatus, dungeon->requiredItemLevel, player->GetAverageItemLevel());
1801 }
1802
1803 return lock;
1804}
1805
1807{
1808 uint8 kicks = GroupsStore[guid].GetKicksLeft();
1809 TC_LOG_TRACE("lfg.data.group.kickleft.get", "Group: {}, Kicks left: {}", guid.ToString(), kicks);
1810 return kicks;
1811}
1812
1813void LFGMgr::RestoreState(ObjectGuid guid, char const* debugMsg)
1814{
1815 if (guid.IsParty())
1816 {
1817 LfgGroupData& data = GroupsStore[guid];
1818 TC_LOG_TRACE("lfg.data.group.state.restore", "Group: {} ({}), State: {}, Old state: {}",
1819 guid.ToString(), debugMsg, GetStateString(data.GetState()),
1820 GetStateString(data.GetOldState()));
1821
1822 data.RestoreState();
1823 }
1824 else
1825 {
1826 LfgPlayerData& data = PlayersStore[guid];
1827 TC_LOG_TRACE("lfg.data.player.state.restore", "Player: {} ({}), State: {}, Old state: {}",
1828 guid.ToString(), debugMsg, GetStateString(data.GetState()),
1829 GetStateString(data.GetOldState()));
1830
1831 data.RestoreState();
1832 }
1833}
1834
1836{
1837 if (guid.IsParty())
1838 {
1839 LfgGroupData& data = GroupsStore[guid];
1840 TC_LOG_TRACE("lfg.data.group.state.set", "Group: {}, New state: {}, Previous: {}, Old state: {}",
1841 guid.ToString(), GetStateString(state), GetStateString(data.GetState()),
1842 GetStateString(data.GetOldState()));
1843
1844 data.SetState(state);
1845 }
1846 else
1847 {
1848 LfgPlayerData& data = PlayersStore[guid];
1849 TC_LOG_TRACE("lfg.data.player.state.set", "Player: {}, New state: {}, Previous: {}, OldState: {}",
1850 guid.ToString(), GetStateString(state), GetStateString(data.GetState()),
1851 GetStateString(data.GetOldState()));
1852
1853 data.SetState(state);
1854 }
1855}
1856
1857void LFGMgr::SetVoteKick(ObjectGuid gguid, bool active)
1858{
1859 ASSERT(gguid.IsParty());
1860
1861 LfgGroupData& data = GroupsStore[gguid];
1862 TC_LOG_TRACE("lfg.data.group.votekick.set", "Group: {}, New state: {}, Previous: {}",
1863 gguid.ToString(), active, data.IsVoteKickActive());
1864
1865 data.SetVoteKick(active);
1866}
1867
1869{
1870 TC_LOG_TRACE("lfg.data.group.dungeon.set", "Group: {}, Dungeon: {}", guid.ToString(), dungeon);
1871 GroupsStore[guid].SetDungeon(dungeon);
1872}
1873
1875{
1876 TC_LOG_TRACE("lfg.data.player.role.set", "Player: {}, Roles: {}", guid.ToString(), roles);
1877 PlayersStore[guid].SetRoles(roles);
1878}
1879
1881{
1882 TC_LOG_TRACE("lfg.data.player.dungeon.selected.set", "Player: {}, Dungeons: {}", guid.ToString(), ConcatenateDungeons(dungeons));
1883 PlayersStore[guid].SetSelectedDungeons(dungeons);
1884}
1885
1887{
1888 GroupsStore[guid].DecreaseKicksLeft();
1889 TC_LOG_TRACE("lfg.data.group.kicksleft.decrease", "Group: {}, Kicks: {}", guid.ToString(), GroupsStore[guid].GetKicksLeft());
1890}
1891
1893{
1894 PlayersStore[guid].SetTicket(ticket);
1895}
1896
1898{
1899 TC_LOG_TRACE("lfg.data.player.remove", "Player: {}", guid.ToString());
1900 LfgPlayerDataContainer::iterator it = PlayersStore.find(guid);
1901 if (it != PlayersStore.end())
1902 PlayersStore.erase(it);
1903}
1904
1906{
1907 TC_LOG_TRACE("lfg.data.group.remove", "Group: {}", guid.ToString());
1908 LfgGroupDataContainer::iterator it = GroupsStore.find(guid);
1909 if (it == GroupsStore.end())
1910 return;
1911
1912 LfgState state = GetState(guid);
1913 // If group is being formed after proposal success do nothing more
1914 GuidSet const& players = it->second.GetPlayers();
1915 for (ObjectGuid playerGUID : players)
1916 {
1917 SetGroup(playerGUID, ObjectGuid::Empty);
1918 if (state != LFG_STATE_PROPOSAL)
1919 {
1920 SetState(playerGUID, LFG_STATE_NONE);
1922 }
1923 }
1924 GroupsStore.erase(it);
1925}
1926
1928{
1929 uint8 team = PlayersStore[guid].GetTeam();
1930 TC_LOG_TRACE("lfg.data.player.team.get", "Player: {}, Team: {}", guid.ToString(), team);
1931 return team;
1932}
1933
1935{
1936 uint8 allowedRoles = PLAYER_ROLE_LEADER;
1937 for (uint32 i = 0; i < MAX_SPECIALIZATIONS; ++i)
1938 if (ChrSpecializationEntry const* specialization = sDB2Manager.GetChrSpecializationByIndex(player->GetClass(), i))
1939 allowedRoles |= 1 << (specialization->Role + 1);
1940
1941 return roles & allowedRoles;
1942}
1943
1945{
1946 return GroupsStore[gguid].RemovePlayer(guid);
1947}
1948
1950{
1951 GroupsStore[gguid].AddPlayer(guid);
1952}
1953
1955{
1956 GroupsStore[gguid].SetLeader(leader);
1957}
1958
1960{
1962 team = 0;
1963
1964 PlayersStore[guid].SetTeam(team);
1965}
1966
1968{
1969 return PlayersStore[guid].GetGroup();
1970}
1971
1973{
1974 PlayersStore[guid].SetGroup(group);
1975}
1976
1978{
1979 return GroupsStore[guid].GetPlayers();
1980}
1981
1983{
1984 return GroupsStore[guid].GetPlayerCount();
1985}
1986
1988{
1989 return GroupsStore[guid].GetLeader();
1990}
1991
1993{
1996 return plr1 && plr2
1997 && (plr1->GetSocial()->HasIgnore(guid2, plr2->GetSession()->GetAccountGUID())
1998 || plr2->GetSocial()->HasIgnore(guid1, plr1->GetSession()->GetAccountGUID()));
1999}
2000
2002{
2003 if (Player* player = ObjectAccessor::FindConnectedPlayer(guid))
2004 player->GetSession()->SendLfgRoleChosen(pguid, roles);
2005}
2006
2008{
2009 if (Player* player = ObjectAccessor::FindConnectedPlayer(guid))
2010 player->GetSession()->SendLfgRoleCheckUpdate(roleCheck);
2011}
2012
2013void LFGMgr::SendLfgUpdateStatus(ObjectGuid guid, LfgUpdateData const& data, bool party)
2014{
2015 if (Player* player = ObjectAccessor::FindConnectedPlayer(guid))
2016 player->GetSession()->SendLfgUpdateStatus(data, party);
2017}
2018
2020{
2021 if (Player* player = ObjectAccessor::FindConnectedPlayer(guid))
2022 player->GetSession()->SendLfgJoinResult(data);
2023}
2024
2026{
2027 if (Player* player = ObjectAccessor::FindConnectedPlayer(guid))
2028 player->GetSession()->SendLfgBootProposalUpdate(boot);
2029}
2030
2032{
2033 if (Player* player = ObjectAccessor::FindConnectedPlayer(guid))
2034 player->GetSession()->SendLfgUpdateProposal(proposal);
2035}
2036
2038{
2039 if (Player* player = ObjectAccessor::FindConnectedPlayer(guid))
2040 player->GetSession()->SendLfgQueueStatus(data);
2041}
2042
2044{
2045 return !guid.IsEmpty() && guid.IsParty() && GroupsStore[guid].IsLfgGroup();
2046}
2047
2049{
2050 if (guid.IsParty())
2051 {
2052 GuidSet const& players = GetPlayers(guid);
2053 ObjectGuid pguid = players.empty() ? ObjectGuid::Empty : (*players.begin());
2054 if (!pguid.IsEmpty())
2055 return GetTeam(pguid);
2056 }
2057
2058 return GetTeam(guid);
2059}
2060
2062{
2063 uint8 queueId = GetQueueId(guid);
2064 return QueuesStore[queueId];
2065}
2066
2067bool LFGMgr::AllQueued(GuidList const& check)
2068{
2069 if (check.empty())
2070 return false;
2071
2072 for (GuidList::const_iterator it = check.begin(); it != check.end(); ++it)
2073 {
2074 LfgState state = GetState(*it);
2075 if (state != LFG_STATE_QUEUED)
2076 {
2077 if (state != LFG_STATE_PROPOSAL)
2078 TC_LOG_DEBUG("lfg.allqueued", "Unexpected state found while trying to form new group. Guid: {}, State: {}", (*it).ToString(), GetStateString(state));
2079
2080 return false;
2081 }
2082 }
2083 return true;
2084}
2085
2087{
2088 uint8 queueId = GetQueueId(guid);
2089 LfgQueueContainer::const_iterator itr = QueuesStore.find(queueId);
2090 if (itr != QueuesStore.end())
2091 return itr->second.GetJoinTime(guid);
2092
2093 return 0;
2094}
2095
2096// Only for debugging purposes
2098{
2099 QueuesStore.clear();
2100}
2101
2103{
2104 return (m_options & option) != 0;
2105}
2106
2108{
2109 return m_options;
2110}
2111
2113{
2114 m_options = options;
2115}
2116
2118{
2119 LfgPlayerData& playerData = PlayersStore[guid];
2120 return LfgUpdateData(LFG_UPDATETYPE_UPDATE_STATUS, playerData.GetState(), playerData.GetSelectedDungeons());
2121}
2122
2124{
2125 switch (dungeonId)
2126 {
2127 case 285: // The Headless Horseman
2129 case 286: // The Frost Lord Ahune
2131 case 287: // Coren Direbrew
2133 case 288: // The Crown Chemical Co.
2135 }
2136 return false;
2137}
2138
2139std::string LFGMgr::DumpQueueInfo(bool full)
2140{
2141 uint32 size = uint32(QueuesStore.size());
2142 std::ostringstream o;
2143
2144 o << "Number of Queues: " << size << "\n";
2145 for (LfgQueueContainer::const_iterator itr = QueuesStore.begin(); itr != QueuesStore.end(); ++itr)
2146 {
2147 std::string const& queued = itr->second.DumpQueueInfo();
2148 std::string const& compatibles = itr->second.DumpCompatibleInfo(full);
2149 o << queued << compatibles;
2150 }
2151
2152 return o.str();
2153}
2154
2156{
2157 LfgDungeonSet dungeons;
2158 dungeons.insert(GetDungeon(gguid));
2159 SetSelectedDungeons(guid, dungeons);
2160 SetState(guid, GetState(gguid));
2161 SetGroup(guid, gguid);
2162 AddPlayerToGroup(gguid, guid);
2163}
2164
2166{
2167 if (GetState(guid) != LFG_STATE_NONE)
2168 {
2169 LfgDungeonSet const& dungeons = GetSelectedDungeons(guid);
2170 if (!dungeons.empty())
2171 {
2172 LFGDungeonData const* dungeon = GetLFGDungeon(*dungeons.begin());
2173 if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal))
2174 return true;
2175 }
2176 }
2177
2178 return false;
2179}
2180
2182{
2183 if (!guid.IsParty())
2184 guid = GetGroup(guid);
2185
2186 if (uint32 dungeonId = GetDungeon(guid, true))
2187 if (LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId))
2188 if (uint32(dungeon->map) == map && dungeon->difficulty == difficulty)
2189 return true;
2190
2191 return false;
2192}
2193
2195{
2196 if (id)
2197 if (LFGDungeonData const* dungeon = GetLFGDungeon(id))
2198 return dungeon->Entry();
2199
2200 return 0;
2201}
2202
2203LfgDungeonSet LFGMgr::GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion, uint32 contentTuningReplacementConditionMask)
2204{
2205 LfgDungeonSet randomDungeons;
2206 for (lfg::LFGDungeonContainer::const_iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr)
2207 {
2208 lfg::LFGDungeonData const& dungeon = itr->second;
2209 if (!(dungeon.type == lfg::LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id))))
2210 continue;
2211
2212 if (dungeon.expansion > expansion)
2213 continue;
2214
2215 if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(dungeon.contentTuningId, contentTuningReplacementConditionMask))
2216 if (levels->MinLevel > level || level > levels->MaxLevel)
2217 continue;
2218
2219 randomDungeons.insert(dungeon.Entry());
2220 }
2221 return randomDungeons;
2222}
2223
2224} // namespace lfg
@ CHAR_INS_LFG_DATA
@ CHAR_DEL_LFG_DATA
@ IN_MILLISECONDS
Definition: Common.h:35
DB2Storage< LFGDungeonsEntry > sLFGDungeonsStore("LFGDungeons.db2", &LfgDungeonsLoadInfo::Instance)
DB2Storage< JournalEncounterEntry > sJournalEncounterStore("JournalEncounter.db2", &JournalEncounterLoadInfo::Instance)
#define sDB2Manager
Definition: DB2Stores.h:538
Difficulty
Definition: DBCEnums.h:873
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
@ DIFFICULTY_HEROIC
Definition: DBCEnums.h:876
@ CompletedLFGDungeonWithStrangers
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
@ DISABLE_TYPE_MAP
Definition: DisableMgr.h:29
@ DISABLE_TYPE_LFG_MAP
Definition: DisableMgr.h:35
#define ABORT_MSG
Definition: Errors.h:75
#define ASSERT
Definition: Errors.h:68
bool IsHolidayActive(HolidayIds id)
#define sGroupMgr
Definition: GroupMgr.h:61
#define MAX_GROUP_SIZE
Definition: Group.h:50
#define sInstanceLockMgr
#define sLFGMgr
Definition: LFGMgr.h:507
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:162
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_TRACE(filterType__,...)
Definition: Log.h:153
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
std::list< ObjectGuid > GuidList
Definition: ObjectGuid.h:394
TypeID
Definition: ObjectGuid.h:34
std::set< ObjectGuid > GuidSet
Definition: ObjectGuid.h:393
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
@ FATIGUE_TIMER
Definition: Player.h:508
Role Based Access Control related classes definition.
#define MAX_SPECIALIZATIONS
@ ALLIANCE
@ HORDE
@ HOLIDAY_HALLOWS_END
@ HOLIDAY_LOVE_IS_IN_THE_AIR
@ HOLIDAY_MIDSUMMER_FIRE_FESTIVAL
@ HOLIDAY_BREWFEST
@ GROUP_REMOVEMETHOD_KICK_LFG
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:57
uint32 getMSTime()
Definition: Timer.h:33
@ UNIT_STATE_JUMPING
Definition: Unit.h:273
static Summons Group[]
Definition: boss_urom.cpp:83
Class used to access individual fields of database query result.
Definition: Field.h:90
uint8 GetUInt8() const
Definition: Field.cpp:30
uint16 GetUInt16() const
Definition: Field.cpp:46
float GetFloat() const
Definition: Field.cpp:94
uint32 GetUInt32() const
Definition: Field.cpp:62
GroupReference * next()
Definition: Group.h:197
bool isLFGGroup() const
Definition: Group.cpp:1633
bool AddMember(Player *player)
Definition: Group.cpp:426
void SendUpdate()
Definition: Group.cpp:834
void SetDungeonDifficultyID(Difficulty difficulty)
Definition: Group.cpp:1286
ObjectGuid GetGUID() const
Definition: Group.cpp:1663
uint32 GetMembersCount() const
Definition: Group.h:327
void SetLfgRoles(ObjectGuid guid, uint8 roles)
Definition: Group.cpp:1465
void ConvertToLFG()
Definition: Group.cpp:283
bool RemoveMember(ObjectGuid guid, RemoveMethod method=GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker=ObjectGuid::Empty, const char *reason=nullptr)
Definition: Group.cpp:570
GroupReference * GetFirstMember()
Definition: Group.h:325
bool Create(Player *leader)
Definition: Group.cpp:141
uint32 GetDbStoreId() const
Definition: Group.h:304
Definition: Map.h:189
bool IsDungeon() const
Definition: Map.cpp:3238
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:319
std::string ToString() const
Definition: ObjectGuid.cpp:554
bool IsParty() const
Definition: ObjectGuid.h:335
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
bool HasIgnore(ObjectGuid const &ignoreGuid, ObjectGuid const &ignoreAccountGuid)
Definition: SocialMgr.cpp:189
PlayerSocial * GetSocial() const
Definition: Player.h:1163
UF::UpdateField< UF::PlayerData, 0, TYPEID_PLAYER > m_playerData
Definition: Player.h:2863
bool GetQuestRewardStatus(uint32 quest_id) const
Definition: Player.cpp:16033
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
Definition: Player.cpp:9888
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={})
Definition: Player.cpp:1250
void SetBattlegroundEntryPoint()
Definition: Player.cpp:23560
bool InBattleground() const
Definition: Player.h:2394
bool CanRewardQuest(Quest const *quest, bool msg) const
Definition: Player.cpp:14717
bool HasAchieved(uint32 achievementId) const
Definition: Player.cpp:26751
bool InBattlegroundQueue(bool ignoreArena=false) const
Definition: Player.cpp:24992
WorldSession * GetSession() const
Definition: Player.h:2101
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
bool TeleportToBGEntryPoint()
Definition: Player.cpp:1496
void FinishTaxiFlight()
Definition: Player.cpp:22706
bool IsMirrorTimerActive(MirrorTimerType type) const
Definition: Player.cpp:731
float GetAverageItemLevel() const
Definition: Player.cpp:29020
static void RemoveFromGroup(Group *group, ObjectGuid guid, RemoveMethod method=GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker=ObjectGuid::Empty, char const *reason=nullptr)
Definition: Player.cpp:2189
bool InArena() const
Definition: Player.cpp:25106
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
void RewardQuest(Quest const *quest, LootItemType rewardType, uint32 rewardId, Object *questGiver, bool announce=true)
Definition: Player.cpp:15152
Team GetTeam() const
Definition: Player.h:2235
void setUInt32(const uint8 index, const uint32 value)
Vehicle * GetVehicle() const
Definition: Unit.h:1713
uint8 GetClass() const
Definition: Unit.h:752
ObjectGuid GetCharmedGUID() const
Definition: Unit.h:1190
bool IsAlive() const
Definition: Unit.h:1164
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
bool IsFalling() const
Definition: Unit.cpp:12308
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3831
uint8 GetLevel() const
Definition: Unit.h:746
constexpr uint32 GetMapId() const
Definition: Position.h:201
Map * GetMap() const
Definition: Object.h:624
Map * FindMap() const
Definition: Object.h:625
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
std::string const & GetName() const
Definition: Object.h:555
void SendLfgJoinResult(lfg::LfgJoinResultData const &joinData)
Definition: LFGHandler.cpp:332
void SendLfgTeleportError(lfg::LfgTeleportResult err)
Definition: LFGHandler.cpp:508
ObjectGuid GetAccountGUID() const
void SendLfgPlayerReward(lfg::LfgPlayerRewardData const &lfgPlayerRewardData)
Definition: LFGHandler.cpp:389
bool HasPermission(uint32 permissionId)
uint8 GetExpansion() const
void SendLfgUpdateStatus(lfg::LfgUpdateData const &updateData, bool party)
Definition: LFGHandler.cpp:233
uint8 GetKicksLeft(ObjectGuid gguid)
Get kicks left in current group.
Definition: LFGMgr.cpp:1806
uint32 GetSelectedRandomDungeon(ObjectGuid guid)
Get selected random dungeon.
Definition: LFGMgr.cpp:1712
void _LoadFromDB(Field *fields, ObjectGuid guid)
Load Lfg group info from DB.
Definition: LFGMgr.cpp:71
void InitBoot(ObjectGuid gguid, ObjectGuid kguid, ObjectGuid vguid, std::string const &reason)
Inits new proposal to boot a player.
Definition: LFGMgr.cpp:1262
uint32 GetLFGDungeonEntry(uint32 id)
Return Lfg dungeon entry for given dungeon id.
Definition: LFGMgr.cpp:2194
time_t GetQueueJoinTime(ObjectGuid guid)
Gets queue join time.
Definition: LFGMgr.cpp:2086
void LoadLFGDungeons(bool reload=false)
Loads dungeons from dbc and adds teleport coords.
Definition: LFGMgr.cpp:190
LfgProposalContainer ProposalsStore
Current Role checks.
Definition: LFGMgr.h:499
uint8 GetPlayerCount(ObjectGuid guid)
Gets the player count of given group.
Definition: LFGMgr.cpp:1982
void SetSelectedDungeons(ObjectGuid guid, LfgDungeonSet const &dungeons)
Definition: LFGMgr.cpp:1880
ObjectGuid GetLeader(ObjectGuid guid)
Get leader of the group (using internal data)
Definition: LFGMgr.cpp:1987
void FinishDungeon(ObjectGuid gguid, uint32 dungeonId, Map const *currMap)
Finish the dungeon for the given group. All check are performed using internal lfg data.
Definition: LFGMgr.cpp:1474
void TeleportPlayer(Player *player, bool out, bool fromOpcode=false)
Teleport a player to/from selected dungeon.
Definition: LFGMgr.cpp:1359
void SendLfgUpdateStatus(ObjectGuid guid, LfgUpdateData const &data, bool party)
Definition: LFGMgr.cpp:2013
LfgState GetOldState(ObjectGuid guid)
Get last lfg state (NONE, DUNGEON or FINISHED_DUNGEON)
Definition: LFGMgr.cpp:1652
void AddPlayerToGroup(ObjectGuid gguid, ObjectGuid guid)
Adds player to group.
Definition: LFGMgr.cpp:1949
void SetGroup(ObjectGuid guid, ObjectGuid group)
Sets player group.
Definition: LFGMgr.cpp:1972
LFGDungeonContainer LfgDungeonStore
Stores rewards for random dungeons.
Definition: LFGMgr.h:496
void SendLfgBootProposalUpdate(ObjectGuid guid, LfgPlayerBoot const &boot)
Definition: LFGMgr.cpp:2025
void SetDungeon(ObjectGuid guid, uint32 dungeon)
Definition: LFGMgr.cpp:1868
LfgPlayerBootContainer BootsStore
Current Proposals.
Definition: LFGMgr.h:500
uint8 GetTeam(ObjectGuid guid)
Definition: LFGMgr.cpp:1927
void SetupGroupMember(ObjectGuid guid, ObjectGuid gguid)
Initializes player data after loading group data from DB.
Definition: LFGMgr.cpp:2155
static LFGMgr * instance()
Definition: LFGMgr.cpp:282
void SetTicket(ObjectGuid guid, WorldPackets::LFG::RideTicket const &ticket)
Definition: LFGMgr.cpp:1892
void RestoreState(ObjectGuid guid, char const *debugMsg)
Definition: LFGMgr.cpp:1813
void Update(uint32 diff)
Definition: LFGMgr.cpp:288
std::string DumpQueueInfo(bool full=false)
Dumps the state of the queue - Only for internal testing.
Definition: LFGMgr.cpp:2139
void SendLfgRoleCheckUpdate(ObjectGuid guid, LfgRoleCheck const &roleCheck)
Definition: LFGMgr.cpp:2007
GuidSet const & GetPlayers(ObjectGuid guid)
Definition: LFGMgr.cpp:1977
uint32 GetOptions()
Gets current lfg options.
Definition: LFGMgr.cpp:2107
LfgDungeonSet const & GetDungeonsByRandom(uint32 randomdungeon)
Definition: LFGMgr.cpp:1591
void LeaveLfg(ObjectGuid guid, bool disconnected=false)
Leaves lfg.
Definition: LFGMgr.cpp:629
void UpdateBoot(ObjectGuid guid, bool accept)
Updates player boot proposal with new player answer.
Definition: LFGMgr.cpp:1295
void LoadRewards()
Loads rewards for random dungeons.
Definition: LFGMgr.cpp:121
LfgDungeonSet GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion, uint32 contentTuningReplacementConditionMask)
Returns all random and seasonal dungeons for given level and expansion.
Definition: LFGMgr.cpp:2203
WorldPackets::LFG::RideTicket const * GetTicket(ObjectGuid guid) const
Gets unique join queue data.
Definition: LFGMgr.cpp:705
LfgLockMap GetLockedDungeons(ObjectGuid guid)
Get locked dungeons.
Definition: LFGMgr.cpp:1728
void SendLfgJoinResult(ObjectGuid guid, LfgJoinResultData const &data)
Definition: LFGMgr.cpp:2019
LfgCachedDungeonContainer CachedDungeonMapStore
Queues.
Definition: LFGMgr.h:493
bool isOptionEnabled(uint32 option)
Checks if given lfg option is enabled.
Definition: LFGMgr.cpp:2102
void UpdateRoleCheck(ObjectGuid gguid, ObjectGuid guid=ObjectGuid::Empty, uint8 roles=PLAYER_ROLE_NONE)
Updates the role check with player answer.
Definition: LFGMgr.cpp:721
void Clean()
Clears queue - Only for internal testing.
Definition: LFGMgr.cpp:2097
bool IsVoteKickActive(ObjectGuid gguid)
Get current vote kick state.
Definition: LFGMgr.cpp:1669
LfgRoleCheckContainer RoleChecksStore
Definition: LFGMgr.h:498
void SetOptions(uint32 options)
Sets new lfg options.
Definition: LFGMgr.cpp:2112
uint32 m_lfgProposalId
used to check interval of update
Definition: LFGMgr.h:489
uint8 RemovePlayerFromGroup(ObjectGuid gguid, ObjectGuid guid)
Removes a player from a group.
Definition: LFGMgr.cpp:1944
LFGDungeonData const * GetLFGDungeon(uint32 id)
Definition: LFGMgr.cpp:181
uint32 GetDungeonMapId(ObjectGuid guid)
Get the map id of the current dungeon.
Definition: LFGMgr.cpp:1686
void RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdateType type)
Definition: LFGMgr.cpp:1162
void RemovePlayerData(ObjectGuid guid)
Definition: LFGMgr.cpp:1897
LfgRewardContainer RewardMapStore
Stores all dungeons by groupType.
Definition: LFGMgr.h:495
void SetState(ObjectGuid guid, LfgState state)
Definition: LFGMgr.cpp:1835
void SendLfgRoleChosen(ObjectGuid guid, ObjectGuid pguid, uint8 roles)
Definition: LFGMgr.cpp:2001
bool selectedRandomLfgDungeon(ObjectGuid guid)
Check if given guid applied for random dungeon.
Definition: LFGMgr.cpp:2165
void GetCompatibleDungeons(LfgDungeonSet *dungeons, GuidSet const &players, LfgLockPartyMap *lockMap, std::vector< std::string const * > *playersMissingRequirement, bool isContinue)
Definition: LFGMgr.cpp:820
bool inLfgDungeonMap(ObjectGuid guid, uint32 map, Difficulty difficulty)
Check if given guid applied for given map and difficulty. Used to know.
Definition: LFGMgr.cpp:2181
void SetLeader(ObjectGuid gguid, ObjectGuid leader)
Sets the leader of the group.
Definition: LFGMgr.cpp:1954
LfgGroupDataContainer GroupsStore
Player data.
Definition: LFGMgr.h:502
void UpdateProposal(uint32 proposalId, ObjectGuid guid, bool accept)
Updates proposal to join dungeon with player answer.
Definition: LFGMgr.cpp:1054
LfgState GetState(ObjectGuid guid)
Get current lfg state.
Definition: LFGMgr.cpp:1635
LFGQueue & GetQueue(ObjectGuid guid)
Definition: LFGMgr.cpp:2061
bool IsLfgGroup(ObjectGuid guid)
Check if given group guid is lfg.
Definition: LFGMgr.cpp:2043
void SetRoles(ObjectGuid guid, uint8 roles)
Sets player lfg roles.
Definition: LFGMgr.cpp:1874
uint8 GetQueueId(ObjectGuid guid)
Returns queue id.
Definition: LFGMgr.cpp:2048
uint32 m_options
used as internal counter for proposals
Definition: LFGMgr.h:490
void RemoveGroupData(ObjectGuid guid)
Removes saved group data.
Definition: LFGMgr.cpp:1905
void _SaveToDB(ObjectGuid guid, uint32 db_guid)
Definition: LFGMgr.cpp:100
static bool CheckGroupRoles(LfgRolesMap &groles)
Checks if given roles match, modifies given roles map with new roles.
Definition: LFGMgr.cpp:880
uint32 GetDungeon(ObjectGuid guid, bool asId=true)
Get current dungeon.
Definition: LFGMgr.cpp:1679
uint8 FilterClassRoles(Player *player, uint8 roles)
Definition: LFGMgr.cpp:1934
void OnDungeonEncounterDone(ObjectGuid gguid, std::array< uint32, 4 > const &dungeonEncounterId, Map const *currMap)
Check dungeon completion on encounter completion.
Definition: LFGMgr.cpp:1451
LfgPlayerDataContainer PlayersStore
Current player kicks.
Definition: LFGMgr.h:501
LfgQueueContainer QueuesStore
Stores config options.
Definition: LFGMgr.h:492
uint32 AddProposal(LfgProposal &proposal)
Add a new Proposal.
Definition: LFGMgr.cpp:1040
uint8 GetRoles(ObjectGuid guid)
Get current player roles.
Definition: LFGMgr.cpp:1699
void SetVoteKick(ObjectGuid gguid, bool active)
Definition: LFGMgr.cpp:1857
bool IsSeasonActive(uint32 dungeonId)
Checks if Seasonal dungeon is active.
Definition: LFGMgr.cpp:2123
bool AllQueued(GuidList const &check)
Checks if all players are queued.
Definition: LFGMgr.cpp:2067
LfgType GetDungeonType(uint32 dungeon)
Definition: LFGMgr.cpp:1626
void DecreaseKicksLeft(ObjectGuid guid)
Definition: LFGMgr.cpp:1886
LfgDungeonSet const & GetSelectedDungeons(ObjectGuid guid)
Get selected dungeons.
Definition: LFGMgr.cpp:1706
static bool HasIgnore(ObjectGuid guid1, ObjectGuid guid2)
Checks if given players are ignoring each other.
Definition: LFGMgr.cpp:1992
static void SendLfgQueueStatus(ObjectGuid guid, LfgQueueStatusData const &data)
Sends queue status to player.
Definition: LFGMgr.cpp:2037
ObjectGuid GetGroup(ObjectGuid guid)
Gets player group.
Definition: LFGMgr.cpp:1967
void SetTeam(ObjectGuid guid, uint8 team)
Sets player team.
Definition: LFGMgr.cpp:1959
LfgReward const * GetRandomDungeonReward(uint32 dungeon, uint8 level)
Gets the random dungeon reward corresponding to given dungeon and player level.
Definition: LFGMgr.cpp:1605
void MakeNewGroup(LfgProposal const &proposal)
Definition: LFGMgr.cpp:947
void JoinLfg(Player *player, uint8 roles, LfgDungeonSet &dungeons)
Join Lfg with selected roles, dungeons and comment.
Definition: LFGMgr.cpp:399
void SendLfgUpdateProposal(ObjectGuid guid, LfgProposal const &proposal)
Definition: LFGMgr.cpp:2031
LfgUpdateData GetLfgStatus(ObjectGuid guid)
Returns current lfg status.
Definition: LFGMgr.cpp:2117
uint32 m_QueueTimer
Definition: LFGMgr.h:488
void AddQueueData(ObjectGuid guid, time_t joinTime, LfgDungeonSet const &dungeons, LfgRolesMap const &rolesMap)
Definition: LFGQueue.cpp:188
time_t GetJoinTime(ObjectGuid guid) const
Definition: LFGQueue.cpp:633
void AddToQueue(ObjectGuid guid, bool reAdd=false)
Definition: LFGQueue.cpp:123
void UpdateWaitTimeAvg(int32 waitTime, uint32 dungeonId)
Definition: LFGQueue.cpp:201
void RemoveFromQueue(ObjectGuid guid)
Definition: LFGQueue.cpp:138
void UpdateWaitTimeHealer(int32 waitTime, uint32 dungeonId)
Definition: LFGQueue.cpp:215
void UpdateWaitTimeTank(int32 waitTime, uint32 dungeonId)
Definition: LFGQueue.cpp:208
void UpdateWaitTimeDps(int32 waitTime, uint32 dungeonId)
Definition: LFGQueue.cpp:222
bool IsVoteKickActive() const
void SetVoteKick(bool active)
LfgState GetState() const
void SetState(LfgState state)
LfgState GetOldState() const
LfgState GetOldState() const
void SetState(LfgState state)
LfgState GetState() const
LfgDungeonSet const & GetSelectedDungeons() const
#define sWorld
Definition: World.h:931
@ CONFIG_MAX_PLAYER_LEVEL
Definition: World.h:259
@ CONFIG_LFG_OPTIONSMASK
Definition: World.h:381
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP
Definition: World.h:111
bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const *ref, uint8 flags)
Definition: DisableMgr.cpp:285
time_t GetGameTime()
Definition: GameTime.cpp:44
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
constexpr std::size_t size()
Definition: UpdateField.h:796
Definition: LFG.cpp:24
@ LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION
Definition: LFG.h:98
@ LFG_LOCKSTATUS_TOO_LOW_LEVEL
Definition: LFG.h:99
@ LFG_LOCKSTATUS_RAID_LOCKED
Definition: LFG.h:103
@ LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE
Definition: LFG.h:101
@ LFG_LOCKSTATUS_MISSING_ITEM
Definition: LFG.h:109
@ LFG_LOCKSTATUS_TOO_HIGH_LEVEL
Definition: LFG.h:100
@ LFG_LOCKSTATUS_MISSING_ACHIEVEMENT
Definition: LFG.h:111
@ LFG_LOCKSTATUS_NOT_IN_SEASON
Definition: LFG.h:110
@ LFG_LOCKSTATUS_QUEST_NOT_COMPLETED
Definition: LFG.h:108
@ LFG_HEALERS_NEEDED
Definition: LFG.h:33
@ LFG_TANKS_NEEDED
Definition: LFG.h:32
@ LFG_DPS_NEEDED
Definition: LFG.h:34
@ LFG_OPTION_ENABLE_DUNGEON_FINDER
Definition: LFGMgr.h:49
@ LFG_OPTION_ENABLE_RAID_BROWSER
Definition: LFGMgr.h:50
std::map< ObjectGuid, uint8 > LfgRolesMap
Definition: LFG.h:135
LfgUpdateType
Definition: LFG.h:48
@ LFG_UPDATETYPE_ROLECHECK_FAILED
Definition: LFG.h:53
@ LFG_UPDATETYPE_GROUP_FOUND
Definition: LFG.h:57
@ LFG_UPDATETYPE_ADDED_TO_QUEUE
Definition: LFG.h:58
@ LFG_UPDATETYPE_UPDATE_STATUS
Definition: LFG.h:61
@ LFG_UPDATETYPE_PROPOSAL_FAILED
Definition: LFG.h:55
@ LFG_UPDATETYPE_PROPOSAL_DECLINED
Definition: LFG.h:56
@ LFG_UPDATETYPE_REMOVED_FROM_QUEUE
Definition: LFG.h:54
@ LFG_UPDATETYPE_PROPOSAL_BEGIN
Definition: LFG.h:60
@ LFG_UPDATETYPE_JOIN_QUEUE
Definition: LFG.h:52
@ LFG_UPDATETYPE_JOIN_QUEUE_INITIAL
Definition: LFG.h:64
@ LFG_SPELL_DUNGEON_COOLDOWN
Definition: LFGMgr.h:59
@ LFG_TIME_BOOT
Definition: LFGMgr.h:56
@ LFG_GROUP_KICK_VOTES_NEEDED
Definition: LFGMgr.h:62
@ LFG_TIME_ROLECHECK
Definition: LFGMgr.h:55
@ LFG_QUEUEUPDATE_INTERVAL
Definition: LFGMgr.h:58
@ LFG_SPELL_DUNGEON_DESERTER
Definition: LFGMgr.h:60
LfgType
Determines the type of instance.
Definition: LFGMgr.h:75
@ LFG_TYPE_NONE
Definition: LFGMgr.h:76
@ LFG_TYPE_RANDOM
Definition: LFGMgr.h:82
@ LFG_TYPE_RAID
Definition: LFGMgr.h:78
@ LFG_TYPE_DUNGEON
Definition: LFGMgr.h:77
@ LFG_TYPE_HEROIC
Definition: LFGMgr.h:81
LfgAnswer
Answer state (Also used to check compatibilites)
Definition: LFG.h:116
@ LFG_ANSWER_AGREE
Definition: LFG.h:119
@ LFG_ANSWER_PENDING
Definition: LFG.h:117
@ LFG_ANSWER_DENY
Definition: LFG.h:118
std::string GetStateString(LfgState state)
Definition: LFG.cpp:75
LfgTeleportResult
Teleport errors.
Definition: LFGMgr.h:95
@ LFG_TELEPORT_RESULT_EXHAUSTION
Definition: LFGMgr.h:101
@ LFG_TELEPORT_RESULT_FALLING
Definition: LFGMgr.h:99
@ LFG_TELEPORT_RESULT_NO_RETURN_LOCATION
Definition: LFGMgr.h:102
@ LFG_TELEPORT_RESULT_ON_TRANSPORT
Definition: LFGMgr.h:100
@ LFG_TELEPORT_RESULT_IMMUNE_TO_SUMMONS
Definition: LFGMgr.h:103
@ LFG_TELEPORT_RESULT_NONE
Definition: LFGMgr.h:97
@ LFG_TELEPORT_RESULT_DEAD
Definition: LFGMgr.h:98
std::set< uint32 > LfgDungeonSet
Definition: LFG.h:132
@ LFG_ROLECHECK_WRONG_ROLES
Definition: LFGMgr.h:148
@ LFG_ROLECHECK_MISSING_ROLE
Definition: LFGMgr.h:147
@ LFG_ROLECHECK_ABORTED
Definition: LFGMgr.h:149
@ LFG_ROLECHECK_DEFAULT
Definition: LFGMgr.h:144
@ LFG_ROLECHECK_FINISHED
Definition: LFGMgr.h:145
@ LFG_ROLECHECK_NO_ROLE
Definition: LFGMgr.h:150
@ LFG_ROLECHECK_INITIALITING
Definition: LFGMgr.h:146
@ LFG_FLAG_SEASONAL
Definition: LFGMgr.h:69
std::string ConcatenateDungeons(LfgDungeonSet const &dungeons)
Definition: LFG.cpp:26
std::pair< LfgRewardContainer::const_iterator, LfgRewardContainer::const_iterator > LfgRewardContainerBounds
Definition: LFGMgr.h:164
@ PLAYER_ROLE_DAMAGE
Definition: LFG.h:43
@ PLAYER_ROLE_ANY
Definition: LFG.h:44
@ 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
std::map< ObjectGuid, LfgLockMap > LfgLockPartyMap
Definition: LFG.h:134
LfgState
Definition: LFG.h:74
@ LFG_STATE_RAIDBROWSER
Definition: LFG.h:82
@ LFG_STATE_ROLECHECK
Definition: LFG.h:76
@ LFG_STATE_FINISHED_DUNGEON
Definition: LFG.h:81
@ LFG_STATE_DUNGEON
Definition: LFG.h:80
@ LFG_STATE_PROPOSAL
Definition: LFG.h:78
@ LFG_STATE_NONE
Definition: LFG.h:75
@ LFG_STATE_QUEUED
Definition: LFG.h:77
std::map< uint32, LfgLockInfoData > LfgLockMap
Definition: LFG.h:133
@ LFG_PROPOSAL_SUCCESS
Definition: LFGMgr.h:90
@ LFG_PROPOSAL_FAILED
Definition: LFGMgr.h:89
@ LFG_JOIN_RANDOM_COOLDOWN_PLAYER
Definition: LFGMgr.h:126
@ LFG_JOIN_NO_SLOTS
Definition: LFGMgr.h:118
@ LFG_JOIN_MEMBERS_NOT_PRESENT
Definition: LFGMgr.h:121
@ LFG_JOIN_ROLE_CHECK_FAILED
Definition: LFGMgr.h:130
@ LFG_JOIN_RANDOM_COOLDOWN_PARTY
Definition: LFGMgr.h:127
@ LFG_JOIN_TOO_MANY_MEMBERS
Definition: LFGMgr.h:128
@ LFG_JOIN_CANT_USE_DUNGEONS
Definition: LFGMgr.h:129
@ LFG_JOIN_OK
Definition: LFGMgr.h:115
@ LFG_JOIN_MISMATCHED_SLOTS
Definition: LFGMgr.h:119
@ LFG_JOIN_NO_LFG_OBJECT
Definition: LFGMgr.h:117
@ LFG_JOIN_DESERTER_PLAYER
Definition: LFGMgr.h:124
@ LFG_JOIN_INVALID_SLOT
Definition: LFGMgr.h:123
@ LFG_JOIN_DESERTER_PARTY
Definition: LFGMgr.h:125
@ RBAC_PERM_JOIN_DUNGEON_FINDER
Definition: RBAC.h:59
uint32 target_mapId
Definition: ObjectMgr.h:460
float target_Orientation
Definition: ObjectMgr.h:464
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
uint32 contentTuningId
Definition: LFGMgr.h:304
Difficulty difficulty
Definition: LFGMgr.h:305
uint32 finalDungeonEncounterId
Definition: LFGMgr.h:309
uint16 requiredItemLevel
Definition: LFGMgr.h:308
std::string name
Definition: LFGMgr.h:299
uint32 Entry() const
Definition: LFGMgr.h:312
std::vector< std::string const * > playersMissingRequirement
Definition: LFGMgr.h:183
LfgJoinResult result
Definition: LFGMgr.h:180
LfgLockPartyMap lockmap
Definition: LFGMgr.h:182
Stores information of a current vote to kick someone from a group.
Definition: LFGMgr.h:285
std::string reason
Player guid to be kicked (can't vote)
Definition: LFGMgr.h:290
time_t cancelTime
Definition: LFGMgr.h:286
LfgAnswerContainer votes
Vote in progress.
Definition: LFGMgr.h:288
bool inProgress
Time left to vote.
Definition: LFGMgr.h:287
ObjectGuid victim
Player votes (-1 not answer | 0 Not agree | 1 agree)
Definition: LFGMgr.h:289
Stores player data related to proposal to join.
Definition: LFGMgr.h:245
LfgAnswer accept
Proposed role.
Definition: LFGMgr.h:248
Stores group data related to proposal to join.
Definition: LFGMgr.h:254
ObjectGuid leader
Proposal group (0 if new)
Definition: LFGMgr.h:263
uint32 dungeonId
Proposal Id.
Definition: LFGMgr.h:260
GuidList queues
Determines if it's new group or not.
Definition: LFGMgr.h:267
LfgProposalPlayerContainer players
Show order in update window.
Definition: LFGMgr.h:269
bool isNew
Dungeon Encounters.
Definition: LFGMgr.h:266
LfgProposalState state
Dungeon to join.
Definition: LFGMgr.h:261
ObjectGuid group
State of the proposal.
Definition: LFGMgr.h:262
Reward info.
Definition: LFGMgr.h:234
uint32 firstQuest
Definition: LFGMgr.h:239
uint32 otherQuest
Definition: LFGMgr.h:240
Stores all rolecheck info of a group that wants to join.
Definition: LFGMgr.h:274
LfgDungeonSet dungeons
State of the rolecheck.
Definition: LFGMgr.h:278
LfgRolesMap roles
Time when the rolecheck will fail.
Definition: LFGMgr.h:276
LfgRoleCheckState state
Player selected roles.
Definition: LFGMgr.h:277
time_t cancelTime
Definition: LFGMgr.h:275
ObjectGuid leader
Random Dungeon Id.
Definition: LFGMgr.h:280
uint32 rDungeonId
Dungeons group is applying for (expanded random dungeons)
Definition: LFGMgr.h:279
LfgUpdateType updateType
Definition: LFGMgr.h:195