diff options
author | Spp <spp@jorge.gr> | 2010-05-31 20:25:21 +0200 |
---|---|---|
committer | Spp <spp@jorge.gr> | 2010-05-31 20:25:21 +0200 |
commit | 824b1303cedd1ce9fed7435982b08e96798f1e70 (patch) | |
tree | 54fd62d176156a2befe1e596b94833523137c0e7 /src/game | |
parent | 248782448c91aaa15a918d117a92f4ceaae0d77c (diff) |
Dungeon Finder:
- Add Rolechecks
- Can Join and Leave queue
* No Find group implementation, it just adds u to the queue.
* Still missing some join queue restrictions.
--HG--
branch : trunk
Diffstat (limited to 'src/game')
-rw-r--r-- | src/game/Group.cpp | 7 | ||||
-rw-r--r-- | src/game/LFG.h | 10 | ||||
-rw-r--r-- | src/game/LFGHandler.cpp | 162 | ||||
-rw-r--r-- | src/game/LFGMgr.cpp | 655 | ||||
-rw-r--r-- | src/game/LFGMgr.h | 117 | ||||
-rw-r--r-- | src/game/Opcodes.cpp | 6 | ||||
-rw-r--r-- | src/game/World.cpp | 3 | ||||
-rw-r--r-- | src/game/WorldSession.cpp | 6 | ||||
-rw-r--r-- | src/game/WorldSession.h | 11 |
9 files changed, 932 insertions, 45 deletions
diff --git a/src/game/Group.cpp b/src/game/Group.cpp index e877e7acb4c..acd19e02838 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -34,7 +34,7 @@ #include "InstanceSaveMgr.h" #include "MapInstanced.h" #include "Util.h" -#include "LFG.h" +#include "LFGMgr.h" Group::Group() { @@ -346,6 +346,9 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method) { BroadcastGroupUpdate(); + if (!isBGGroup()) + sLFGMgr.Leave(NULL, this); + // remove member and change leader (if need) only if strong more 2 members _before_ member remove if (GetMembersCount() > (isBGGroup() ? 1 : 2)) // in BG group case allow 1 members group { @@ -362,6 +365,7 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method) if (method == 1) { data.Initialize(SMSG_GROUP_UNINVITE, 0); + player->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_LEADER); player->GetSession()->SendPacket(&data); } @@ -434,6 +438,7 @@ void Group::Disband(bool hideDestroy) player->SetOriginalGroup(NULL); else player->SetGroup(NULL); + player->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_GROUP_DISBAND); player->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_LEADER); } diff --git a/src/game/LFG.h b/src/game/LFG.h index d30d694f43e..2581f08b9b9 100644 --- a/src/game/LFG.h +++ b/src/game/LFG.h @@ -24,11 +24,11 @@ enum LfgRoles { - NONE = 0x00, - LEADER = 0x01, - TANK = 0x02, - HEALER = 0x04, - DAMAGE = 0x08, + ROL_NONE = 0x00, + ROL_LEADER = 0x01, + ROL_TANK = 0x02, + ROL_HEALER = 0x04, + ROL_DAMAGE = 0x08, }; enum LfgUpdateType diff --git a/src/game/LFGHandler.cpp b/src/game/LFGHandler.cpp index 462b3c3e16b..0746973ff4c 100644 --- a/src/game/LFGHandler.cpp +++ b/src/game/LFGHandler.cpp @@ -22,6 +22,74 @@ #include "WorldPacket.h" #include "Player.h" +void WorldSession::HandleLfgJoinOpcode(WorldPacket &recv_data) +{ + sLog.outDebug("CMSG_LFG_JOIN"); + + uint8 numDungeons; + uint32 dungeon; + uint32 roles; + std::string comment; + + recv_data >> roles; + recv_data.read_skip<uint8>(); // unk - always 0 + recv_data.read_skip<uint8>(); // unk - always 0 + recv_data >> numDungeons; + if (!numDungeons) + { + sLog.outError("Invalid CMSG_LFG_JOIN packet sent by %s", GetPlayer()->GetName()); + recv_data.rpos(recv_data.wpos()); + return; + } + + GetPlayer()->m_lookingForGroup.roles = uint8(roles); + for (int8 i = 0 ; i < numDungeons; ++i) + { + recv_data >> dungeon; + // remove the type from the dungeon entry + GetPlayer()->m_lookingForGroup.applyDungeons.insert((dungeon & 0x00FFFFFF)); + } + + recv_data >> numDungeons; // unk - always 3 + for (int8 i = 0 ; i < numDungeons; ++i) + recv_data.read_skip<uint8>(); // unk - always 0 + + recv_data >> comment; + + GetPlayer()->m_lookingForGroup.comment = comment; + sLFGMgr.Join(GetPlayer()); +} + +void WorldSession::HandleLfgLeaveOpcode(WorldPacket & /*recv_data*/) +{ + sLog.outDebug("CMSG_LFG_LEAVE"); + + // Check cheating - only leader can leave the queue + if (Group *grp = GetPlayer()->GetGroup()) + { + if (grp->GetLeaderGUID() != GetPlayer()->GetGUID()) + return; + else + sLFGMgr.Leave(GetPlayer(), grp); + } + else + sLFGMgr.Leave(GetPlayer()); +} + +void WorldSession::HandleLfgSetRolesOpcode(WorldPacket &recv_data) +{ + sLog.outDebug("CMSG_LFG_SET_ROLES"); + + uint8 roles; + recv_data >> roles; // Player Group Roles + + Group *grp = GetPlayer()->GetGroup(); + if (!grp) + return; + GetPlayer()->m_lookingForGroup.roles = roles; + sLFGMgr.UpdateRoleCheck(grp, GetPlayer()); +} + void WorldSession::HandleSetLfgCommentOpcode(WorldPacket & recv_data) { sLog.outDebug("CMSG_SET_LFG_COMMENT"); @@ -44,7 +112,7 @@ void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket &/*recv_data* sLFGMgr.SendLfgPartyInfo(GetPlayer()); } -void WorldSession::SendLfgUpdatePlayer(uint8 updateType, uint32 dungeonEntry /* = 0*/) +void WorldSession::SendLfgUpdatePlayer(uint8 updateType) { bool queued = false; bool extrainfo = false; @@ -62,7 +130,7 @@ void WorldSession::SendLfgUpdatePlayer(uint8 updateType, uint32 dungeonEntry /* break; } sLog.outDebug("SMSG_LFG_UPDATE_PLAYER"); - WorldPacket data(SMSG_LFG_UPDATE_PLAYER, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + !dungeonEntry ? 4 : GetPlayer()->m_lookingForGroup.applyDungeons.size() * 4 + GetPlayer()->m_lookingForGroup.comment.length())); + WorldPacket data(SMSG_LFG_UPDATE_PLAYER, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + GetPlayer()->m_lookingForGroup.applyDungeons.size() * 4 + GetPlayer()->m_lookingForGroup.comment.length())); data << uint8(updateType); // Lfg Update type data << uint8(extrainfo); // Extra info if (extrainfo) @@ -71,25 +139,17 @@ void WorldSession::SendLfgUpdatePlayer(uint8 updateType, uint32 dungeonEntry /* data << uint8(0); // unk - Always 0 data << uint8(0); // unk - Always 0 - if (dungeonEntry) - { - data << uint8(1); - data << uint32(dungeonEntry); - } - else - { - uint8 size = GetPlayer()->m_lookingForGroup.applyDungeons.size(); - data << uint8(size); + uint8 size = GetPlayer()->m_lookingForGroup.applyDungeons.size(); + data << uint8(size); - for (LfgDungeonSet::const_iterator it = GetPlayer()->m_lookingForGroup.applyDungeons.begin(); it != GetPlayer()->m_lookingForGroup.applyDungeons.end(); ++it) - data << uint32(*it); - } + for (LfgDungeonSet::const_iterator it = GetPlayer()->m_lookingForGroup.applyDungeons.begin(); it != GetPlayer()->m_lookingForGroup.applyDungeons.end(); ++it) + data << uint32(*it); data << GetPlayer()->m_lookingForGroup.comment; } SendPacket(&data); } -void WorldSession::SendLfgUpdateParty(uint8 updateType, uint32 dungeonEntry /* = 0*/) +void WorldSession::SendLfgUpdateParty(uint8 updateType) { bool join = false; bool extrainfo = false; @@ -116,7 +176,7 @@ void WorldSession::SendLfgUpdateParty(uint8 updateType, uint32 dungeonEntry /* = } sLog.outDebug("SMSG_LFG_UPDATE_PARTY"); - WorldPacket data(SMSG_LFG_UPDATE_PARTY, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + 1 + !dungeonEntry ? 4 : GetPlayer()->m_lookingForGroup.applyDungeons.size() * 4 + GetPlayer()->m_lookingForGroup.comment.length())); + WorldPacket data(SMSG_LFG_UPDATE_PARTY, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + 1 + GetPlayer()->m_lookingForGroup.applyDungeons.size() * 4 + GetPlayer()->m_lookingForGroup.comment.length())); data << uint8(updateType); // Lfg Update type data << uint8(extrainfo); // Extra info if (extrainfo) @@ -125,21 +185,67 @@ void WorldSession::SendLfgUpdateParty(uint8 updateType, uint32 dungeonEntry /* = data << uint8(queued); // Join the queue data << uint8(0); // unk - Always 0 data << uint8(0); // unk - Always 0 + for (uint8 i = 0; i < 3; ++i) + data << uint8(0); // unk - Always 0 - if (dungeonEntry) - { - data << uint8(1); - data << uint32(dungeonEntry); - } - else - { - uint8 size = GetPlayer()->m_lookingForGroup.applyDungeons.size(); - data << uint8(size); + uint8 size = GetPlayer()->m_lookingForGroup.applyDungeons.size(); + data << uint8(size); + + for (LfgDungeonSet::const_iterator it = GetPlayer()->m_lookingForGroup.applyDungeons.begin(); it != GetPlayer()->m_lookingForGroup.applyDungeons.end(); ++it) + data << uint32(*it); - for (LfgDungeonSet::const_iterator it = GetPlayer()->m_lookingForGroup.applyDungeons.begin(); it != GetPlayer()->m_lookingForGroup.applyDungeons.end(); ++it) - data << uint32(*it); - } data << GetPlayer()->m_lookingForGroup.comment; } SendPacket(&data); } + +void WorldSession::SendLfgRoleChosen(uint64 guid, uint8 roles) +{ + sLog.outDebug("SMSG_LFG_ROLE_CHOSEN"); + + WorldPacket data(SMSG_LFG_ROLE_CHOSEN); + data << uint64(guid); // Guid + data << uint8(roles > 0); // Ready + data << uint32(roles); // Roles + SendPacket(&data); +} + +void WorldSession::SendLfgJoinResult(uint8 checkResult, uint8 checkValue) +{ + if (checkResult == LFG_JOIN_PARTY_NOT_MEET_REQS) // Should never happen - its handled in Mgr + return; + + sLog.outDebug("SMSG_LFG_JOIN_RESULT"); + + WorldPacket data(SMSG_LFG_JOIN_RESULT); + data << uint32(checkResult); // Check Result + data << uint32(checkValue); // Check Value + SendPacket(&data); +} + +void WorldSession::SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps) +{ + sLog.outDebug("SMSG_LFG_QUEUE_STATUS"); + WorldPacket data(SMSG_LFG_QUEUE_STATUS); + + data << uint32(dungeon); // Dungeon + data << uint32(avgWaitTime); // Average Wait time + data << uint32(waitTime); // Wait Time + data << uint32(waitTimeTanks); // Wait Tanks + data << uint32(waitTimeHealer); // Wait Healers + data << uint32(waitTimeDps); // Wait Dps + data << uint8(tanks); // Tanks needed + data << uint8(healers); // Healers needed + data << uint8(dps); // Dps needed + data << uint32(queuedTime); // Player wait time in queue + SendPacket(&data); +} + +void WorldSession::SendLfgUpdateSearch(bool update) +{ + sLog.outDebug("SMSG_LFG_UPDATE_SEARCH"); + + WorldPacket data(SMSG_LFG_UPDATE_SEARCH); + data << uint8(update); // In Lfg Queue? + SendPacket(&data); +} diff --git a/src/game/LFGMgr.cpp b/src/game/LFGMgr.cpp index 1601722d896..fffba750180 100644 --- a/src/game/LFGMgr.cpp +++ b/src/game/LFGMgr.cpp @@ -26,26 +26,173 @@ INSTANTIATE_SINGLETON_1(LFGMgr); +/*********************************************************/ +/*** LFG QUEUES ***/ +/*********************************************************/ + +LFGQueue::LFGQueue() +{ + m_LfgQueue.clear(); + avgWaitTime = -1; + waitTimeTanks = -1; + waitTimeHealer = -1; + waitTimeDps = -1; +} + +LFGQueue::~LFGQueue() +{ + m_LfgQueue.clear(); +} + +void LFGQueue::AddToQueue(uint64 guid, LfgQueueInfo* pqInfo) +{ + if (LfgQueueInfo* qInfo = m_LfgQueue[guid]) + delete qInfo; + m_LfgQueue[guid] = pqInfo; + // ATM will only add it to the queue... No find group implementation... yet (on purpose) +} + +bool LFGQueue::RemoveFromQueue(uint64 guid) +{ + if (m_LfgQueue.empty()) + return false; + + LfgQueueInfoMap::iterator itr = m_LfgQueue.find(guid); + if (itr == m_LfgQueue.end()) + return false; + + delete itr->second; + m_LfgQueue.erase(itr); + return true; +} + +LfgQueueInfo* LFGQueue::GetQueueInfo(uint64 guid) +{ + return m_LfgQueue[guid]; +} + +void LFGQueue::Update() +{ + if (m_LfgQueue.empty()) + return; + + Player *plr; + LfgQueueInfo *queue; + time_t currTime = time(NULL); + uint32 queuedTime; + uint8 rol = 0; + int32 waitTime = -1; + for (LfgQueueInfoMap::const_iterator itQueue = m_LfgQueue.begin(); itQueue != m_LfgQueue.end(); ++itQueue) + { + queue = itQueue->second; + // Update queue status + queuedTime = uint32(currTime - queue->joinTime); + for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) + { + plr = objmgr.GetPlayer(itPlayer->first); + if (!plr) + continue; + rol = itPlayer->second; + if (rol & ROL_TANK) + { + if (rol & ROL_HEALER || rol & ROL_DAMAGE) + waitTime = avgWaitTime; + else + waitTime = waitTimeTanks; + } + else if (rol & ROL_HEALER) + { + if (rol & ROL_DAMAGE) + waitTime = avgWaitTime; + else + waitTime = waitTimeDps; + } + plr->GetSession()->SendLfgQueueStatus(queue->dungeonId, waitTime, avgWaitTime, waitTimeTanks, waitTimeHealer, waitTimeDps, queuedTime, queue->tanks, queue->healers, queue->dps); + } + } +} + LFGMgr::LFGMgr() { + m_QueueTimer = 0; + m_update = true; } LFGMgr::~LFGMgr() { + // RewardList to be removed -> query quest system for (LfgRewardList::iterator it = m_RewardList.begin(); it != m_RewardList.end(); ++it) delete *it; m_RewardList.clear(); + // RewardDoneList to be removed -> query quest system for (LfgRewardList::iterator it = m_RewardDoneList.begin(); it != m_RewardDoneList.end(); ++it) delete *it; m_RewardDoneList.clear(); + for(LFGQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) + delete it->second; + m_Queues.clear(); + for (LfgDungeonMap::iterator it = m_DungeonsMap.begin(); it != m_DungeonsMap.end(); ++it) { it->second->clear(); delete it->second; } m_DungeonsMap.clear(); + + for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end(); ++it) + delete it->second; + m_RoleChecks.clear(); +} + +void LFGMgr::Update(uint32 diff) +{ + if (!m_update) + return; + + // Update all players status queue info + if (m_QueueTimer > LFG_QUEUEUPDATE_INTERVAL) + { + m_QueueTimer = 0; + for (LFGQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) + it->second->Update(); + } + else + m_QueueTimer += diff; + + time_t currTime = time(NULL); + + // Remove obsolete role checks + LfgRoleCheckMap::iterator itRoleCheck; + LfgRoleCheck *pRoleCheck; + for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end();) + { + itRoleCheck = it++; + pRoleCheck = itRoleCheck->second; + if (currTime < pRoleCheck->cancelTime) + continue; + pRoleCheck->result = LFG_ROLECHECK_MISSING_ROLE; + + WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + pRoleCheck->dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); + sLog.outDebug("SMSG_LFG_ROLE_CHECK_UPDATE"); + BuildLfgRoleCheck(data, pRoleCheck); + Player *plr = NULL; + for (LfgRolesMap::const_iterator itRoles = pRoleCheck->roles.begin(); itRoles != pRoleCheck->roles.end(); ++itRoles) + { + plr = objmgr.GetPlayer(itRoles->first); + if (!plr) + continue; + plr->GetSession()->SendPacket(&data); + plr->m_lookingForGroup.applyDungeons.clear(); + plr->m_lookingForGroup.roles = 0; + + if (itRoles->first == pRoleCheck->leader) + plr->GetSession()->SendLfgJoinResult(LFG_JOIN_FAILED, pRoleCheck->result); + } + delete pRoleCheck; + m_RoleChecks.erase(itRoleCheck); + } } /// <summary> @@ -53,7 +200,7 @@ LFGMgr::~LFGMgr() /// </summary> void LFGMgr::InitLFG() { - // Fill reward data + // Fill reward data (to be removed -> query quest system) LfgReward *reward; for (uint8 i = 0; i <= LFG_REWARD_DATA_SIZE; ++i) { @@ -84,13 +231,430 @@ void LFGMgr::InitLFG() } // Initialize dungeonMap m_DungeonsMap[LFG_ALL_DUNGEONS] = GetAllDungeons(); - /* This will be used later. m_DungeonsMap[LFG_RANDOM_CLASSIC] = GetDungeonsByRandom(LFG_RANDOM_CLASSIC); m_DungeonsMap[LFG_RANDOM_BC_NORMAL] = GetDungeonsByRandom(LFG_RANDOM_BC_NORMAL); m_DungeonsMap[LFG_RANDOM_BC_HEROIC] = GetDungeonsByRandom(LFG_RANDOM_BC_HEROIC); m_DungeonsMap[LFG_RANDOM_LK_NORMAL] = GetDungeonsByRandom(LFG_RANDOM_LK_NORMAL); m_DungeonsMap[LFG_RANDOM_LK_HEROIC] = GetDungeonsByRandom(LFG_RANDOM_LK_HEROIC); - */ +} + +/// <summary> +/// Adds the player to lfg queue +/// </summary> +/// <param name="plr">Player</param> +void LFGMgr::Join(Player *plr) +{ + Group *grp = plr->GetGroup(); + + // TODO - 2010-05-27 Anyone can init rolecheck when already in a LFD Group? + if (grp && grp->GetLeaderGUID() != plr->GetGUID()) + return; + + // Previous checks before joining + LfgJoinResult result = LFG_JOIN_OK; + if (plr->InBattleGround() || plr->InArena()) + result = LFG_JOIN_USING_BG_SYSTEM; + else if (plr->HasAura(LFG_SPELL_DESERTER)) + result = LFG_JOIN_DESERTER; + else if (plr->HasAura(LFG_SPELL_COOLDOWN)) + result = LFG_JOIN_RANDOM_COOLDOWN; + else + { + // Check if all dungeons are valid + for (LfgDungeonSet::const_iterator it = plr->m_lookingForGroup.applyDungeons.begin(); it != plr->m_lookingForGroup.applyDungeons.end(); ++it) + { + if ((m_DungeonsMap[LFG_ALL_DUNGEONS])->find(*it) == (m_DungeonsMap[LFG_ALL_DUNGEONS])->end()) + { + result = LFG_JOIN_DUNGEON_INVALID; + break; + } + } + } + + if (grp && result == LFG_JOIN_OK) + { + if (grp->GetMembersCount() > MAXGROUPSIZE) + result = LFG_JOIN_TOO_MUCH_MEMBERS; + else + { + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL && result == LFG_JOIN_OK; itr = itr->next()) + { + if (Player *plrg = itr->getSource()) + { + if (plrg->HasAura(LFG_SPELL_DESERTER)) + result = LFG_JOIN_PARTY_DESERTER; + else if (plrg->HasAura(LFG_SPELL_COOLDOWN)) + result = LFG_JOIN_PARTY_RANDOM_COOLDOWN; + } + else + result = LFG_JOIN_DISCONNECTED; + } + } + } + + if (result != LFG_JOIN_OK) + { + plr->m_lookingForGroup.applyDungeons.clear(); + plr->m_lookingForGroup.roles = 0; + plr->GetSession()->SendLfgJoinResult(result, 0); + return; + } + + if (grp) + { + Player *plrg = NULL; + for (GroupReference *itr = plr->GetGroup()->GetFirstMember(); itr != NULL; itr = itr->next()) + { + plrg = itr->getSource(); // Not null, checked earlier + plrg->m_lookingForGroup.applyDungeons = plr->m_lookingForGroup.applyDungeons; + plrg->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_JOIN_PROPOSAL); + } + UpdateRoleCheck(grp, plr); + } + else + { + plr->GetSession()->SendLfgJoinResult(LFG_JOIN_OK, 0); + plr->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_JOIN_PROPOSAL); + + // Add player to queue + LfgQueueInfo *pqInfo; + uint8 groupType = 0; + uint8 tanks = LFG_TANKS_NEEDED; + uint8 healers = LFG_HEALERS_NEEDED; + uint8 dps = LFG_DPS_NEEDED; + if (plr->m_lookingForGroup.roles & ROL_TANK) + --tanks; + else if (plr->m_lookingForGroup.roles & ROL_HEALER) + --healers; + else + --dps; + m_update = false; + for (LfgDungeonSet::const_iterator it = plr->m_lookingForGroup.applyDungeons.begin(); it != plr->m_lookingForGroup.applyDungeons.end(); ++it) + { + groupType = GetDungeonGroupType(*it); + pqInfo = m_Queues[groupType] ? m_Queues[groupType]->GetQueueInfo(plr->GetGUID()) : NULL; + // if exist we have already added the player with another dungeon sharing same GroupType + if (pqInfo) + continue; + pqInfo = new LfgQueueInfo(); + pqInfo->dungeonId = *it; + pqInfo->joinTime = time_t(time(NULL)); + pqInfo->tanks = tanks; + pqInfo->healers = healers; + pqInfo->dps = dps; + pqInfo->roles[plr->GetGUID()] = plr->m_lookingForGroup.roles; + if (!m_Queues[groupType]) + m_Queues[groupType] = new LFGQueue(); + m_Queues[groupType]->AddToQueue(plr->GetGUID(), pqInfo); + } + m_update = true; + } +} + +/// <summary> +/// Leave the lfg queue +/// </summary> +/// <param name="plr">Player (could be NULL)</param> +/// <param name="grp">Group (could be NULL)</param> +void LFGMgr::Leave(Player *plr, Group *grp /* = NULL*/) +{ + uint64 guid = grp ? grp->GetGUID() : plr ? plr->GetGUID() : 0; + assert(guid); + + // Check if player was in a rolecheck + if (grp) + { + LfgRoleCheckMap::iterator itRoleCheck = m_RoleChecks.find(GUID_LOPART(grp->GetGUID())); + if (itRoleCheck != m_RoleChecks.end()) + { + UpdateRoleCheck(grp); // No player to update role = LFG_ROLECHECK_ABORTED + return; + } + } + + // Check if player/group was in the queue + bool inQueue = false; + for (LFGQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) + inQueue |= it->second->RemoveFromQueue(guid); + + // Not in queue + if (!inQueue) + return; + + if (grp) + { + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + if (Player *plrg = itr->getSource()) + { + plrg->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + plrg->m_lookingForGroup.applyDungeons.clear(); + plrg->m_lookingForGroup.roles = 0; + } + } + else + { + plr->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + plr->m_lookingForGroup.applyDungeons.clear(); + plr->m_lookingForGroup.roles = 0; + } +} + +/// <summary> +/// Update the Role check info with the player selected role. +/// </summary> +/// <param name="grp">Group</param> +/// <param name="plr">Player</param> +void LFGMgr::UpdateRoleCheck(Group *grp, Player *plr /* = NULL*/) +{ + assert(grp); + + uint32 rolecheckId = GUID_LOPART(grp->GetGUID()); + LfgRoleCheck *pRoleCheck = NULL; + LfgRolesMap check_roles; + LfgRoleCheckMap::iterator itRoleCheck = m_RoleChecks.find(rolecheckId); + bool newRoleCheck = itRoleCheck == m_RoleChecks.end(); + if (newRoleCheck) + { + if (!grp->IsLeader(plr->GetGUID())) + return; + + pRoleCheck = new LfgRoleCheck(); + pRoleCheck->cancelTime = time_t(time(NULL)) + LFG_TIME_ROLECHECK; + pRoleCheck->result = LFG_ROLECHECK_INITIALITING; + pRoleCheck->leader = plr->GetGUID(); + + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + if (Player *plrg = itr->getSource()) + pRoleCheck->roles[plrg->GetGUID()] = 0; + + pRoleCheck->dungeons = plr->m_lookingForGroup.applyDungeons; + } + else + pRoleCheck = itRoleCheck->second; + + LfgLockStatusMap *playersLockMap = NULL; + if (plr) + { + // Player selected no role. + if (plr->m_lookingForGroup.roles < ROL_TANK) + pRoleCheck->result = LFG_ROLECHECK_NO_ROLE; + else + { + // Check if all players have selected a role + pRoleCheck->roles[plr->GetGUID()] = plr->m_lookingForGroup.roles; + uint8 size = 0; + for (LfgRolesMap::const_iterator itRoles = pRoleCheck->roles.begin(); itRoles != pRoleCheck->roles.end() && itRoles->second != ROL_NONE; ++itRoles) + ++size; + + if (pRoleCheck->roles.size() == size) + { + // use temporal var to check roles, CheckGroupRoles modifies the roles + for (LfgRolesMap::const_iterator itRoles = pRoleCheck->roles.begin(); itRoles != pRoleCheck->roles.end(); ++itRoles) + check_roles[itRoles->first] = itRoles->second; + + if (!CheckGroupRoles(check_roles)) // Group is not posible + pRoleCheck->result = LFG_ROLECHECK_WRONG_ROLES; + else + { + // Check if we can find a dungeon for that group + pRoleCheck->result = LFG_ROLECHECK_FINISHED; + if (pRoleCheck->dungeons.size() > 1) + playersLockMap = GetPartyLockStatusDungeons(plr, &pRoleCheck->dungeons); + else + { + LfgDungeonSet::const_iterator it = pRoleCheck->dungeons.begin(); + LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(*it); + if (dungeon && dungeon->type == LFG_TYPE_RANDOM) + playersLockMap = GetPartyLockStatusDungeons(plr, m_DungeonsMap[*it]); + else + playersLockMap = GetPartyLockStatusDungeons(plr, &pRoleCheck->dungeons); + } + } + } + } + } + else + pRoleCheck->result = LFG_ROLECHECK_ABORTED; + + WorldSession *session; + WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + pRoleCheck->dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); + sLog.outDebug("SMSG_LFG_ROLE_CHECK_UPDATE"); + BuildLfgRoleCheck(data, pRoleCheck); + + Player *plrg = NULL; + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + plrg = itr->getSource(); + if (!plrg) + continue; + + session = plrg->GetSession(); + if (!newRoleCheck && plr) + session->SendLfgRoleChosen(plr->GetGUID(), plr->m_lookingForGroup.roles); + session->SendPacket(&data); + + switch(pRoleCheck->result) + { + case LFG_ROLECHECK_INITIALITING: + continue; + case LFG_ROLECHECK_FINISHED: + if (!playersLockMap) + { + session->SendLfgUpdateParty(LFG_UPDATETYPE_ADDED_TO_QUEUE); + } + else + { + if (grp->IsLeader(plrg->GetGUID())) + { + uint32 size = 0; + for (LfgLockStatusMap::const_iterator it = playersLockMap->begin(); it != playersLockMap->end(); ++it) + size += 8 + 4 + it->second->size() * (4 + 4); + WorldPacket data(SMSG_LFG_JOIN_RESULT, 4 + 4 + size); + sLog.outDebug("SMSG_LFG_JOIN_RESULT"); + data << uint32(LFG_JOIN_PARTY_NOT_MEET_REQS); // Check Result + data << uint32(0); // Check Value (always 0 when PartyNotMeetReqs + BuildPartyLockDungeonBlock(data, playersLockMap); + session->SendPacket(&data); + } + session->SendLfgUpdateParty(LFG_UPDATETYPE_ROLECHECK_FAILED); + plrg->m_lookingForGroup.applyDungeons.clear(); + plrg->m_lookingForGroup.roles = 0; + } + break; + default: + if (grp->IsLeader(plrg->GetGUID())) + session->SendLfgJoinResult(LFG_JOIN_FAILED, pRoleCheck->result); + session->SendLfgUpdateParty(LFG_UPDATETYPE_ROLECHECK_FAILED); + plrg->m_lookingForGroup.applyDungeons.clear(); + plrg->m_lookingForGroup.roles = 0; + break; + } + } + + if (pRoleCheck->result == LFG_ROLECHECK_FINISHED) + { + // Add qroup to queue + LfgQueueInfo *pqInfo; + uint8 groupType = 0; + uint8 tanks = LFG_TANKS_NEEDED; + uint8 healers = LFG_HEALERS_NEEDED; + uint8 dps = LFG_DPS_NEEDED; + for (LfgRolesMap::const_iterator it = check_roles.begin(); it != check_roles.end(); ++it) + { + if (it->second & ROL_TANK) + --tanks; + else if (it->second & ROL_HEALER) + --healers; + else + --dps; + } + uint64 guid = grp->GetGUID(); + m_update = false; + for (LfgDungeonSet::const_iterator it = pRoleCheck->dungeons.begin(); it != pRoleCheck->dungeons.end(); ++it) + { + groupType = GetDungeonGroupType(*it); + pqInfo = m_Queues[groupType] ? m_Queues[groupType]->GetQueueInfo(guid) : NULL; + // if exist we have already added the player with another dungeon sharing same GroupType + if (pqInfo) + continue; + pqInfo = new LfgQueueInfo(); + pqInfo->dungeonId = *it; + pqInfo->joinTime = time_t(time(NULL)); + pqInfo->tanks = tanks; + pqInfo->healers = healers; + pqInfo->dps = dps; + for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + if (Player *plrg = itr->getSource()) + pqInfo->roles[plrg->GetGUID()] = plrg->m_lookingForGroup.roles; + } + if (!m_Queues[groupType]) + m_Queues[groupType] = new LFGQueue(); + m_Queues[groupType]->AddToQueue(guid, pqInfo); + } + m_update = true; + } + + if (pRoleCheck->result != LFG_ROLECHECK_INITIALITING) + { + delete itRoleCheck->second; + m_RoleChecks.erase(itRoleCheck); + } + else if (newRoleCheck) + m_RoleChecks[rolecheckId] = pRoleCheck; +} + +/// <summary> +/// Check if a group can be formed with the given group +/// </summary> +/// <param name="grp">Group</param> +/// <returns>bool</returns> +bool LFGMgr::CheckGroupRoles(LfgRolesMap &groles) +{ + if (!groles.size()) + return false; + + uint8 damage = 0; + uint8 tank = 0; + uint8 healer = 0; + uint64 tguid = 0; + uint64 hguid = 0; + uint64 dguid = 0; + uint64 guid = 0; + uint8 rol = 0; + + for (LfgRolesMap::const_iterator it = groles.begin(); it != groles.end(); ++it) + { + guid = it->first; + rol = it->second; + + if (rol == ROL_NONE || rol == ROL_LEADER) + return false; + + if (rol & ROL_TANK) + if (!tank) + { + tguid = guid; + ++tank; + } + else + { + if (groles[tguid] == ROL_TANK) + tguid = guid; + groles[tguid] -= ROL_TANK; + return CheckGroupRoles(groles); + } + + if (rol & ROL_HEALER) + if (!healer) + { + hguid = guid; + ++healer; + } + else + { + if (groles[hguid] == ROL_HEALER) + hguid = guid; + groles[hguid] -= ROL_HEALER; + return CheckGroupRoles(groles); + } + + if (rol & ROL_DAMAGE) + if (damage < 3) + { + if (!damage) + dguid = guid; + ++damage; + } + else + { + if (groles[dguid] == ROL_DAMAGE) + dguid = guid; + groles[dguid] -= ROL_DAMAGE; + return CheckGroupRoles(groles); + } + } + return true; } @@ -100,6 +664,58 @@ void LFGMgr::InitLFG() // --------------------------------------------------------------------------// /// <summary> +/// Build lfgRolecheck packet +/// </summary> +/// <param name="data">WorldPacket</param> +/// <param name="plr">Player</param> +/// <param name="status">Player status in LFG system</param> +void LFGMgr::BuildLfgRoleCheck(WorldPacket &data, LfgRoleCheck *pRoleCheck) +{ + assert(pRoleCheck); + + Player *plr; + uint8 roles; + + data << uint32(pRoleCheck->result); // Check result + data << uint8(pRoleCheck->result == LFG_ROLECHECK_INITIALITING); + data << uint8(pRoleCheck->dungeons.size()); // Number of dungeons + LFGDungeonEntry const *dungeon; + for (LfgDungeonSet::iterator it = pRoleCheck->dungeons.begin(); it != pRoleCheck->dungeons.end(); ++it) + { + dungeon = sLFGDungeonStore.LookupEntry(*it); // not null - been checked at join time + data << uint32(dungeon->Entry()); // Dungeon + } + + data << uint8(pRoleCheck->roles.size()); // Players in group + // Leader info MUST be sent 1st :S + roles = pRoleCheck->roles[pRoleCheck->leader]; + data << uint64(pRoleCheck->leader); // Guid + data << uint8(roles > 0); // Ready + data << uint32(roles); // Roles + plr = objmgr.GetPlayer(pRoleCheck->leader); + if (plr) + data << uint8(plr->getLevel()); // Level + else + data << uint8(0); + + for (LfgRolesMap::const_iterator itPlayers = pRoleCheck->roles.begin(); itPlayers != pRoleCheck->roles.end(); ++itPlayers) + { + if (itPlayers->first == pRoleCheck->leader) + continue; + + roles = itPlayers->second; + data << uint64(itPlayers->first); // Guid + data << uint8(roles > 0); // Ready + data << uint32(roles); // Roles + plr = objmgr.GetPlayer(pRoleCheck->leader); + if (plr) + data << uint8(plr->getLevel()); // Level + else + data << uint8(0); + } +} + +/// <summary> /// Build and Send LFG lock player info and reward /// </summary> /// <param name="plr">Player</param> @@ -117,9 +733,7 @@ void LFGMgr::SendLfgPlayerInfo(Player *plr) sLog.outDebug("SMSG_LFG_PLAYER_INFO"); WorldPacket data(SMSG_LFG_PLAYER_INFO, 1 + rsize * (4 + 1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4) + 4 + lsize * (4 + 4)); if (!randomlist) - { data << uint8(0); - } else { data << uint8(randomlist->size()); // Random Dungeon count @@ -252,13 +866,23 @@ LfgLockStatusMap* LFGMgr::GetPartyLockStatusDungeons(Player *plr, LfgDungeonSet return NULL; Player *plrg; + LfgLockStatusSet *dungeonSet = NULL; LfgLockStatusMap *dungeonMap = new LfgLockStatusMap(); for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { plrg = itr->getSource(); if (!plrg || plrg == plr) continue; - (*dungeonMap)[plrg->GetGUID()] = GetPlayerLockStatusDungeons(plrg, dungeons); + + dungeonSet = GetPlayerLockStatusDungeons(plrg, dungeons); + if (dungeonSet) + (*dungeonMap)[plrg->GetGUID()] = dungeonSet; + } + + if (!dungeonMap->size()) + { + delete dungeonMap; + dungeonMap = NULL; } return dungeonMap; } @@ -317,6 +941,11 @@ LfgLockStatusSet* LFGMgr::GetPlayerLockStatusDungeons(Player *plr, LfgDungeonSet list->insert(lockstatus); } } + if (!list->size()) + { + delete list; + list = NULL; + } return list; } @@ -438,3 +1067,17 @@ LfgReward* LFGMgr::GetRandomDungeonReward(uint32 dungeon, bool done, uint8 level } return done ? m_RewardDoneList.at(index) : m_RewardList.at(index); } + +/// <summary> +/// Given a Dungeon id returns the dungeon Group Type +/// </summary> +/// <param name="dungeonId">Dungeon id</param> +/// <returns>uint8: GroupType</returns> +uint8 LFGMgr::GetDungeonGroupType(uint32 dungeonId) +{ + LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(dungeonId); + if (!dungeon) + return 0; + + return dungeon->grouptype; +} diff --git a/src/game/LFGMgr.h b/src/game/LFGMgr.h index d54fb0f3c1b..809db7b6929 100644 --- a/src/game/LFGMgr.h +++ b/src/game/LFGMgr.h @@ -24,6 +24,16 @@ #include "Group.h" #include "LFG.h" +enum LFGenum +{ + LFG_TIME_ROLECHECK = 2*MINUTE, + LFG_TANKS_NEEDED = 1, + LFG_HEALERS_NEEDED = 1, + LFG_DPS_NEEDED = 3, + LFG_QUEUEUPDATE_INTERVAL = 15000, + LFG_SPELL_COOLDOWN = 71328, + LFG_SPELL_DESERTER = 71041, +}; enum LfgType { @@ -35,6 +45,19 @@ enum LfgType LFG_TYPE_RANDOM = 6, }; +enum LfgGroupType +{ + LFG_GROUPTYPE_CLASSIC = 1, + LFG_GROUPTYPE_BC_NORMAL = 2, + LFG_GROUPTYPE_BC_HEROIC = 3, + LFG_GROUPTYPE_WTLK_NORMAL = 4, + LFG_GROUPTYPE_WTLK_HEROIC = 5, + LFG_GROUPTYPE_CLASSIC_RAID = 6, + LFG_GROUPTYPE_BC_RAID = 7, + LFG_GROUPTYPE_WTLK_RAID_10 = 8, + LFG_GROUPTYPE_WTLK_RAID_25 = 9, +}; + enum LfgLockStatusType { LFG_LOCKSTATUS_OK = 0, // Internal use only @@ -51,6 +74,39 @@ enum LfgLockStatusType LFG_LOCKSTATUS_NOT_IN_SEASON = 1031, }; +enum LfgJoinResult +{ + LFG_JOIN_OK = 0, // Joined (no client msg) + LFG_JOIN_FAILED = 1, // RoleCheck Failed + LFG_JOIN_GROUPFULL = 2, // Your group is full + LFG_JOIN_UNK3 = 3, // No client reaction + LFG_JOIN_INTERNAL_ERROR = 4, // Internal LFG Error + LFG_JOIN_NOT_MEET_REQS = 5, // You do not meet the requirements for the chosen dungeons + LFG_JOIN_PARTY_NOT_MEET_REQS = 6, // One or more party members do not meet the requirements for the chosen dungeons + LFG_JOIN_MIXED_RAID_DUNGEON = 7, // You cannot mix dungeons, raids, and random when picking dungeons + LFG_JOIN_MULTI_REALM = 8, // The dungeon you chose does not support players from multiple realms + LFG_JOIN_DISCONNECTED = 9, // One or more party members are pending invites or disconnected + LFG_JOIN_PARTY_INFO_FAILED = 10, // Could not retrieve information about some party members + LFG_JOIN_DUNGEON_INVALID = 11, // One or more dungeons was not valid + LFG_JOIN_DESERTER = 12, // You can not queue for dungeons until your deserter debuff wears off + LFG_JOIN_PARTY_DESERTER = 13, // One or more party members has a deserter debuff + LFG_JOIN_RANDOM_COOLDOWN = 14, // You can not queue for random dungeons while on random dungeon cooldown + LFG_JOIN_PARTY_RANDOM_COOLDOWN = 15, // One or more party members are on random dungeon cooldown + LFG_JOIN_TOO_MUCH_MEMBERS = 16, // You can not enter dungeons with more that 5 party members + LFG_JOIN_USING_BG_SYSTEM = 17, // You can not use the dungeon system while in BG or arenas + LFG_JOIN_FAILED2 = 18, // RoleCheck Failed +}; + +enum LfgRoleCheckResult +{ + LFG_ROLECHECK_FINISHED = 1, // Role check finished + LFG_ROLECHECK_INITIALITING = 2, // Role check begins + LFG_ROLECHECK_MISSING_ROLE = 3, // Someone didn't selected a role after 2 mins + LFG_ROLECHECK_WRONG_ROLES = 4, // Can't form a group with that role selection + LFG_ROLECHECK_ABORTED = 5, // Someone leave the group + LFG_ROLECHECK_NO_ROLE = 6, // Someone selected no role +}; + enum LfgRandomDungeonEntries { LFG_ALL_DUNGEONS = 0, @@ -131,6 +187,54 @@ typedef std::vector<LfgReward*> LfgRewardList; typedef std::map<uint64, LfgLockStatusSet*> LfgLockStatusMap; typedef std::map<uint32, LfgDungeonSet*> LfgDungeonMap; +typedef std::map<uint64, int8> LfgAnswerMap; +typedef std::map<uint64, uint8> LfgRolesMap; +typedef std::set<uint64> LfgGuidSet; + +// Stores player or group queue info +struct LfgQueueInfo +{ + time_t joinTime; // Player queue join time (to calculate wait times) + uint32 dungeonId; // Selected Player/Group Dungeon + LfgRolesMap roles; // Selected Player Role/s + uint8 tanks; // Tanks needed + uint8 healers; // Healers needed + uint8 dps; // Dps needed +}; + +// Stores all rolecheck info of a group that wants to join LFG +struct LfgRoleCheck +{ + time_t cancelTime; + LfgRolesMap roles; + LfgRoleCheckResult result; + LfgDungeonSet dungeons; + uint64 leader; +}; + +typedef std::map<uint64, LfgQueueInfo*> LfgQueueInfoMap; +typedef std::map<uint32, LfgRoleCheck*> LfgRoleCheckMap; + +class LFGQueue +{ + public: + LFGQueue(); + ~LFGQueue(); + + void Update(); + void AddToQueue(uint64 guid, LfgQueueInfo *pqInfo); + bool RemoveFromQueue(uint64 guid); + LfgQueueInfo* GetQueueInfo(uint64 guid); + private: + LfgQueueInfoMap m_LfgQueue; + int32 avgWaitTime; + int32 waitTimeTanks; + int32 waitTimeHealer; + int32 waitTimeDps; +}; + +typedef std::map<uint8, LFGQueue *> LFGQueueMap; + class LFGMgr { public: @@ -140,22 +244,35 @@ public: void InitLFG(); void SendLfgPlayerInfo(Player *plr); void SendLfgPartyInfo(Player *plr); + void Join(Player *plr); + void Leave(Player *plr, Group *grp = NULL); + void UpdateRoleCheck(Group *grp, Player *plr = NULL); + void Update(uint32 diff); private: + void BuildLfgRoleCheck(WorldPacket &data, LfgRoleCheck *pRoleCheck); void BuildAvailableRandomDungeonList(WorldPacket &data, Player *plr); void BuildRewardBlock(WorldPacket &data, uint32 dungeon, Player *plr); void BuildPlayerLockDungeonBlock(WorldPacket &data, LfgLockStatusSet *lockSet); void BuildPartyLockDungeonBlock(WorldPacket &data, LfgLockStatusMap *lockMap); + bool CheckGroupRoles(LfgRolesMap &groles); + LfgLockStatusMap* GetPartyLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons); LfgLockStatusSet* GetPlayerLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons); LfgDungeonSet* GetRandomDungeons(uint8 level, uint8 expansion); LfgDungeonSet* GetDungeonsByRandom(uint32 randomdungeon); LfgDungeonSet* GetAllDungeons(); LfgReward* GetRandomDungeonReward(uint32 dungeon, bool done, uint8 level); + uint8 GetDungeonGroupType(uint32 dungeon); LfgRewardList m_RewardList; LfgRewardList m_RewardDoneList; LfgDungeonMap m_DungeonsMap; + + LFGQueueMap m_Queues; + LfgRoleCheckMap m_RoleChecks; + uint32 m_QueueTimer; + bool m_update; }; #define sLFGMgr Trinity::Singleton<LFGMgr>::Instance() diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp index d45e264cfd6..0b67199b4ea 100644 --- a/src/game/Opcodes.cpp +++ b/src/game/Opcodes.cpp @@ -888,8 +888,8 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x359*/ { "MSG_MOVE_START_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, /*0x35A*/ { "MSG_MOVE_STOP_ASCEND", STATUS_LOGGEDIN, &WorldSession::HandleMovementOpcodes }, /*0x35B*/ { "SMSG_ARENA_TEAM_STATS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x35C*/ { "CMSG_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, - /*0x35D*/ { "CMSG_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x35C*/ { "CMSG_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::HandleLfgJoinOpcode }, + /*0x35D*/ { "CMSG_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::HandleLfgLeaveOpcode }, /*0x35E*/ { "CMSG_SEARCH_LFG_JOIN", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, /*0x35F*/ { "CMSG_SEARCH_LFG_LEAVE", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, /*0x360*/ { "SMSG_UPDATE_LFG_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, @@ -902,7 +902,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x367*/ { "SMSG_LFG_UPDATE_PLAYER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x368*/ { "SMSG_LFG_UPDATE_PARTY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x369*/ { "SMSG_LFG_UPDATE_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x36A*/ { "CMSG_LFG_SET_ROLES", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, + /*0x36A*/ { "CMSG_LFG_SET_ROLES", STATUS_LOGGEDIN, &WorldSession::HandleLfgSetRolesOpcode }, /*0x36B*/ { "CMSG_LFG_SET_NEEDS", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, /*0x36C*/ { "CMSG_LFG_SET_BOOT_VOTE", STATUS_LOGGEDIN, &WorldSession::Handle_NULL }, /*0x36D*/ { "SMSG_LFG_BOOT_PROPOSAL_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, diff --git a/src/game/World.cpp b/src/game/World.cpp index e3943b7dd05..04f0c46a7d5 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1969,6 +1969,9 @@ void World::Update(uint32 diff) sOutdoorPvPMgr.Update(diff); RecordTimeDiff("UpdateOutdoorPvPMgr"); + sLFGMgr.Update(diff); + RecordTimeDiff("UpdateLFGMgr"); + // execute callbacks from sql queries that were queued recently UpdateResultQueue(); RecordTimeDiff("UpdateResultQueue"); diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index ea78eb22fb8..bc737717840 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -42,6 +42,7 @@ #include "SocialMgr.h" #include "zlib/zlib.h" #include "ScriptMgr.h" +#include "LFGMgr.h" /// WorldSession constructor WorldSession::WorldSession(uint32 id, WorldSocket *sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale) : @@ -314,6 +315,11 @@ void WorldSession::LogoutPlayer(bool Save) if (_player) { + sLFGMgr.Leave(_player); + GetPlayer()->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + GetPlayer()->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); + GetPlayer()->GetSession()->SendLfgUpdateSearch(false); + if (uint64 lguid = GetPlayer()->GetLootGUID()) DoLootRelease(lguid); diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index a8abe9054d7..c17f3e3f3e6 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -695,8 +695,15 @@ class WorldSession void HandleSetLfgCommentOpcode(WorldPacket & recv_data); void HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& recv_data); void HandleLfgPartyLockInfoRequestOpcode(WorldPacket& recv_data); - void SendLfgUpdatePlayer(uint8 updateType, uint32 dungeonEntry = 0); - void SendLfgUpdateParty(uint8 updateType, uint32 dungeonEntry = 0); + void HandleLfgJoinOpcode(WorldPacket &recv_data); + void HandleLfgLeaveOpcode(WorldPacket & /*recv_data*/); + void HandleLfgSetRolesOpcode(WorldPacket &recv_data); + void SendLfgUpdatePlayer(uint8 updateType); + void SendLfgUpdateParty(uint8 updateType); + void SendLfgRoleChosen(uint64 guid, uint8 roles); + void SendLfgUpdateSearch(bool update); + void SendLfgJoinResult(uint8 checkResult, uint8 checkValue); + void SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps); // Arena Team void HandleInspectArenaTeamsOpcode(WorldPacket& recv_data); |