void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck* pRoleCheck) { ASSERT(pRoleCheck); LfgDungeonSet dungeons; if (pRoleCheck->rDungeonId) dungeons.insert(pRoleCheck->rDungeonId); else dungeons = pRoleCheck->dungeons; Log.Debug("LfgHandler", "SMSG_LFG_ROLE_CHECK_UPDATE %u", GetPlayer()->GetGUID()); WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); data << uint32(pRoleCheck->state); // Check result data << uint8(pRoleCheck->state == LFG_ROLECHECK_INITIALITING); data << uint8(dungeons.size()); // Number of dungeons if (!dungeons.empty()) { for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) { DBC::Structures::LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*it); data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon } } data << uint8(pRoleCheck->roles.size()); // Players in group if (!pRoleCheck->roles.empty()) { // Leader info MUST be sent 1st :S uint64 guid = pRoleCheck->leader; uint8 roles = pRoleCheck->roles.find(guid)->second; data << uint64(guid); // Guid data << uint8(roles > 0); // Ready data << uint32(roles); // Roles Player* player = objmgr.GetPlayer(GET_LOWGUID_PART(guid)); data << uint8(player ? player->getLevel() : 0); // Level for (LfgRolesMap::const_iterator it = pRoleCheck->roles.begin(); it != pRoleCheck->roles.end(); ++it) { if (it->first == pRoleCheck->leader) continue; guid = it->first; roles = it->second; data << uint64(guid); // Guid data << uint8(roles > 0); // Ready data << uint32(roles); // Roles player = objmgr.GetPlayer(GET_LOWGUID_PART(guid)); data << uint8(player ? player->getLevel() : 0); // Level } } SendPacket(&data); }
void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck* pRoleCheck) { ASSERT(pRoleCheck); LfgDungeonSet dungeons; if (pRoleCheck->rDungeonId) dungeons.insert(pRoleCheck->rDungeonId); else dungeons = pRoleCheck->dungeons; sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_ROLE_CHECK_UPDATE [" UI64FMTD "]", GetPlayer()->GetGUID()); WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); data << uint32(pRoleCheck->state); // Check result data << uint8(pRoleCheck->state == LFG_ROLECHECK_INITIALITING); data << uint8(dungeons.size()); // Number of dungeons if (!dungeons.empty()) { for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) { LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*it); data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon } } data << uint8(pRoleCheck->roles.size()); // Players in group if (!pRoleCheck->roles.empty()) { // Leader info MUST be sent 1st :S uint64 guid = pRoleCheck->leader; uint8 roles = pRoleCheck->roles.find(guid)->second; data << uint64(guid); // Guid data << uint8(roles > 0); // Ready data << uint32(roles); // Roles Player* plr = ObjectAccessor::FindPlayer(guid); data << uint8(plr ? plr->getLevel() : 0); // Level for (LfgRolesMap::const_iterator it = pRoleCheck->roles.begin(); it != pRoleCheck->roles.end(); ++it) { if (it->first == pRoleCheck->leader) continue; guid = it->first; roles = it->second; data << uint64(guid); // Guid data << uint8(roles > 0); // Ready data << uint32(roles); // Roles plr = ObjectAccessor::FindPlayer(guid); data << uint8(plr ? plr->getLevel() : 0); // Level } } SendPacket(&data); }
void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck) { LfgDungeonSet dungeons; if (roleCheck.rDungeonId) dungeons.insert(roleCheck.rDungeonId); else dungeons = roleCheck.dungeons; sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_ROLE_CHECK_UPDATE %s", GetPlayerInfo().c_str()); WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + roleCheck.roles.size() * (8 + 1 + 4 + 1)); data << uint32(roleCheck.state); // Check result data << uint8(roleCheck.state == LFG_ROLECHECK_INITIALITING); data << uint8(dungeons.size()); // Number of dungeons if (!dungeons.empty()) { for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) { LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(*it); data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon } } data << uint8(roleCheck.roles.size()); // Players in group if (!roleCheck.roles.empty()) { // Leader info MUST be sent 1st :S uint64 guid = roleCheck.leader; uint8 roles = roleCheck.roles.find(guid)->second; data << uint64(guid); // Guid data << uint8(roles > 0); // Ready data << uint32(roles); // Roles Player* player = ObjectAccessor::FindPlayer(guid); data << uint8(player ? player->getLevel() : 0); // Level for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it) { if (it->first == roleCheck.leader) continue; guid = it->first; roles = it->second; data << uint64(guid); // Guid data << uint8(roles > 0); // Ready data << uint32(roles); // Roles player = ObjectAccessor::FindPlayer(guid); data << uint8(player ? player->getLevel() : 0);// Level } } SendPacket(&data); }
std::string ConcatenateDungeons(LfgDungeonSet const& dungeons) { std::string dungeonstr = ""; if (!dungeons.empty()) { std::ostringstream o; LfgDungeonSet::const_iterator it = dungeons.begin(); o << (*it); for (++it; it != dungeons.end(); ++it) o << ", " << uint32(*it); dungeonstr = o.str(); } return dungeonstr; }
/** Check compatibilities between groups. If group is Matched proposal will be created @param[in] check List of guids to check compatibilities @return LfgCompatibility type of compatibility */ LfgCompatibility LFGQueue::CheckCompatibility(LfgGuidList check) { std::string strGuids = ConcatenateGuids(check); LfgProposal proposal; LfgDungeonSet proposalDungeons; LfgGroupsMap proposalGroups; LfgRolesMap proposalRoles; // Check for correct size if (check.size() > MAXGROUPSIZE || check.empty()) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s): Size wrong - Not compatibles", strGuids.c_str()); return LFG_INCOMPATIBLES_WRONG_GROUP_SIZE; } // Check all-but-new compatiblitity if (check.size() > 2) { uint64 frontGuid = check.front(); check.pop_front(); // Check all-but-new compatibilities (New, A, B, C, D) --> check(A, B, C, D) LfgCompatibility child_compatibles = CheckCompatibility(check); if (child_compatibles < LFG_COMPATIBLES_WITH_LESS_PLAYERS) // Group not compatible { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) child %s not compatibles", strGuids.c_str(), ConcatenateGuids(check).c_str()); SetCompatibles(strGuids, child_compatibles); return child_compatibles; } check.push_front(frontGuid); } // Check if more than one LFG group and number of players joining uint8 numPlayers = 0; uint8 numLfgGroups = 0; for (LfgGuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAXGROUPSIZE; ++it) { uint64 guid = (*it); LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(guid); if (itQueue == QueueDataStore.end()) { TC_LOG_ERROR("lfg.queue.match.compatibility.check", "Guid: [" UI64FMTD "] is not queued but listed as queued!", guid); RemoveFromQueue(guid); return LFG_COMPATIBILITY_PENDING; } // Store group so we don't need to call Mgr to get it later (if it's player group will be 0 otherwise would have joined as group) for (LfgRolesMap::const_iterator it2 = itQueue->second.roles.begin(); it2 != itQueue->second.roles.end(); ++it2) proposalGroups[it2->first] = IS_GROUP_GUID(itQueue->first) ? itQueue->first : 0; numPlayers += itQueue->second.roles.size(); if (sLFGMgr->IsLfgGroup(guid)) { if (!numLfgGroups) proposal.group = guid; ++numLfgGroups; } } // Group with less that MAXGROUPSIZE members always compatible if (check.size() == 1 && numPlayers != MAXGROUPSIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) sigle group. Compatibles", strGuids.c_str()); LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(check.front()); LfgCompatibilityData data(LFG_COMPATIBLES_WITH_LESS_PLAYERS); data.roles = itQueue->second.roles; LFGMgr::CheckGroupRoles(data.roles); UpdateBestCompatibleInQueue(itQueue, strGuids, data.roles); SetCompatibilityData(strGuids, data); return LFG_COMPATIBLES_WITH_LESS_PLAYERS; } if (numLfgGroups > 1) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) More than one Lfggroup (%u)", strGuids.c_str(), numLfgGroups); SetCompatibles(strGuids, LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS); return LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS; } if (numPlayers > MAXGROUPSIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Too much players (%u)", strGuids.c_str(), numPlayers); SetCompatibles(strGuids, LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS); return LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS; } // If it's single group no need to check for duplicate players, ignores, bad roles or bad dungeons as it's been checked before joining if (check.size() > 1) { for (LfgGuidList::const_iterator it = check.begin(); it != check.end(); ++it) { const LfgRolesMap &roles = QueueDataStore[(*it)].roles; for (LfgRolesMap::const_iterator itRoles = roles.begin(); itRoles != roles.end(); ++itRoles) { LfgRolesMap::const_iterator itPlayer; for (itPlayer = proposalRoles.begin(); itPlayer != proposalRoles.end(); ++itPlayer) { if (itRoles->first == itPlayer->first) TC_LOG_ERROR("lfg.queue.match.compatibility.check", "Guids: ERROR! Player multiple times in queue! [" UI64FMTD "]", itRoles->first); else if (sLFGMgr->HasIgnore(itRoles->first, itPlayer->first)) break; } if (itPlayer == proposalRoles.end()) proposalRoles[itRoles->first] = itRoles->second; } } if (uint8 playersize = numPlayers - proposalRoles.size()) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) not compatible, %u players are ignoring each other", strGuids.c_str(), playersize); SetCompatibles(strGuids, LFG_INCOMPATIBLES_HAS_IGNORES); return LFG_INCOMPATIBLES_HAS_IGNORES; } LfgRolesMap debugRoles = proposalRoles; if (!LFGMgr::CheckGroupRoles(proposalRoles)) { std::ostringstream o; for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it) o << ", " << it->first << ": " << GetRolesString(it->second); TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Roles not compatible%s", strGuids.c_str(), o.str().c_str()); SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_ROLES); return LFG_INCOMPATIBLES_NO_ROLES; } LfgGuidList::iterator itguid = check.begin(); proposalDungeons = QueueDataStore[*itguid].dungeons; std::ostringstream o; o << ", " << *itguid << ": (" << ConcatenateDungeons(proposalDungeons) << ")"; for (++itguid; itguid != check.end(); ++itguid) { LfgDungeonSet temporal; LfgDungeonSet &dungeons = QueueDataStore[*itguid].dungeons; o << ", " << *itguid << ": (" << ConcatenateDungeons(dungeons) << ")"; std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin())); proposalDungeons = temporal; } if (proposalDungeons.empty()) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) No compatible dungeons%s", strGuids.c_str(), o.str().c_str()); SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_DUNGEONS); return LFG_INCOMPATIBLES_NO_DUNGEONS; } } else { uint64 gguid = *check.begin(); const LfgQueueData &queue = QueueDataStore[gguid]; proposalDungeons = queue.dungeons; proposalRoles = queue.roles; LFGMgr::CheckGroupRoles(proposalRoles); // assing new roles } // Enough players? if (numPlayers != MAXGROUPSIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Compatibles but not enough players(%u)", strGuids.c_str(), numPlayers); LfgCompatibilityData data(LFG_COMPATIBLES_WITH_LESS_PLAYERS); data.roles = proposalRoles; for (LfgGuidList::const_iterator itr = check.begin(); itr != check.end(); ++itr) UpdateBestCompatibleInQueue(QueueDataStore.find(*itr), strGuids, data.roles); SetCompatibilityData(strGuids, data); return LFG_COMPATIBLES_WITH_LESS_PLAYERS; } uint64 gguid = *check.begin(); proposal.queues = check; proposal.isNew = numLfgGroups != 1 || sLFGMgr->GetOldState(gguid) != LFG_STATE_DUNGEON; if (!sLFGMgr->AllQueued(check)) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Group MATCH but can't create proposal!", strGuids.c_str()); SetCompatibles(strGuids, LFG_COMPATIBLES_BAD_STATES); return LFG_COMPATIBLES_BAD_STATES; } // Create a new proposal proposal.cancelTime = time(NULL) + LFG_TIME_PROPOSAL; proposal.state = LFG_PROPOSAL_INITIATING; proposal.leader = 0; proposal.dungeonId = Trinity::Containers::SelectRandomContainerElement(proposalDungeons); bool leader = false; for (LfgRolesMap::const_iterator itRoles = proposalRoles.begin(); itRoles != proposalRoles.end(); ++itRoles) { // Assing new leader if (itRoles->second & PLAYER_ROLE_LEADER) { if (!leader || !proposal.leader || urand(0, 1)) proposal.leader = itRoles->first; leader = true; } else if (!leader && (!proposal.leader || urand(0, 1))) proposal.leader = itRoles->first; // Assing player data and roles LfgProposalPlayer &data = proposal.players[itRoles->first]; data.role = itRoles->second; data.group = proposalGroups.find(itRoles->first)->second; if (!proposal.isNew && data.group && data.group == proposal.group) // Player from existing group, autoaccept data.accept = LFG_ANSWER_AGREE; } // Mark proposal members as not queued (but not remove queue data) for (LfgGuidList::const_iterator itQueue = proposal.queues.begin(); itQueue != proposal.queues.end(); ++itQueue) { uint64 guid = (*itQueue); RemoveFromNewQueue(guid); RemoveFromCurrentQueue(guid); } sLFGMgr->AddProposal(proposal); TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) MATCH! Group formed", strGuids.c_str()); SetCompatibles(strGuids, LFG_COMPATIBLES_MATCH); return LFG_COMPATIBLES_MATCH; }
void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck* pRoleCheck) { ASSERT(pRoleCheck); LfgDungeonSet dungeons; if (pRoleCheck->rDungeonId) dungeons.insert(pRoleCheck->rDungeonId); else dungeons = pRoleCheck->dungeons; ObjectGuid unkGuid = 0; sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_ROLE_CHECK_UPDATE [" UI64FMTD "]", GetPlayer()->GetGUID()); WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); ByteBuffer dataBuffer; data.WriteBit(unkGuid[0]); data.WriteBit(unkGuid[1]); data.WriteBit(unkGuid[6]); data.WriteBits(pRoleCheck->roles.size(), 21); if (!pRoleCheck->roles.empty()) { ObjectGuid guid = pRoleCheck->leader; uint8 roles = pRoleCheck->roles.find(guid)->second; Player* player = ObjectAccessor::FindPlayer(guid); data.WriteBit(guid[4]); data.WriteBit(guid[1]); data.WriteBit(guid[2]); data.WriteBit(guid[6]); data.WriteBit(roles > 0); data.WriteBit(guid[5]); data.WriteBit(guid[7]); data.WriteBit(guid[0]); data.WriteBit(guid[3]); dataBuffer << uint32(roles); // Roles dataBuffer.WriteByteSeq(guid[0]); dataBuffer.WriteByteSeq(guid[2]); dataBuffer.WriteByteSeq(guid[5]); dataBuffer.WriteByteSeq(guid[4]); dataBuffer.WriteByteSeq(guid[7]); dataBuffer.WriteByteSeq(guid[6]); dataBuffer.WriteByteSeq(guid[1]); dataBuffer.WriteByteSeq(guid[3]); dataBuffer << uint8(player ? player->getLevel() : 0); // Level for (LfgRolesMap::const_reverse_iterator it = pRoleCheck->roles.rbegin(); it != pRoleCheck->roles.rend(); ++it) { if (it->first == pRoleCheck->leader) continue; guid = it->first; roles = it->second; player = ObjectAccessor::FindPlayer(guid); data.WriteBit(guid[4]); data.WriteBit(guid[1]); data.WriteBit(guid[2]); data.WriteBit(guid[6]); data.WriteBit(roles > 0); data.WriteBit(guid[5]); data.WriteBit(guid[7]); data.WriteBit(guid[0]); data.WriteBit(guid[3]); dataBuffer << uint32(roles); // Roles dataBuffer.WriteByteSeq(guid[0]); dataBuffer.WriteByteSeq(guid[2]); dataBuffer.WriteByteSeq(guid[5]); dataBuffer.WriteByteSeq(guid[4]); dataBuffer.WriteByteSeq(guid[7]); dataBuffer.WriteByteSeq(guid[6]); dataBuffer.WriteByteSeq(guid[1]); dataBuffer.WriteByteSeq(guid[3]); dataBuffer << uint8(player ? player->getLevel() : 0); // Level } } data.WriteBit(unkGuid[7]); data.WriteBits(dungeons.size(), 22); data.WriteBit(pRoleCheck->state == LFG_ROLECHECK_INITIALITING); data.WriteBit(unkGuid[3]); data.WriteBit(unkGuid[5]); data.WriteBit(unkGuid[4]); data.WriteBit(unkGuid[2]); data.FlushBits(); data.append(dataBuffer); data.WriteByteSeq(unkGuid[4]); if (!dungeons.empty()) { for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) { LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*it); data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon } } data.WriteByteSeq(unkGuid[6]); data.WriteByteSeq(unkGuid[7]); data.WriteByteSeq(unkGuid[0]); data.WriteByteSeq(unkGuid[3]); data << uint8(1); data.WriteByteSeq(unkGuid[5]); data << uint8(pRoleCheck->state); data.WriteByteSeq(unkGuid[2]); data.WriteByteSeq(unkGuid[1]); SendPacket(&data); }
bool LfgJoinAction::JoinProposal() { ItemCountByQuality visitor; IterateItems(&visitor, ITERATE_ITEMS_IN_EQUIP); bool heroic = urand(0, 100) < 50 && (visitor.count[ITEM_QUALITY_EPIC] >= 3 || visitor.count[ITEM_QUALITY_RARE] >= 10) && bot->getLevel() >= 70; bool random = urand(0, 100) < 25; bool raid = !heroic && (urand(0, 100) < 50 && visitor.count[ITEM_QUALITY_EPIC] >= 5 && (bot->getLevel() == 60 || bot->getLevel() == 70 || bot->getLevel() == 80)); LfgDungeonSet list; vector<uint32> idx; for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) { LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i); if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM && dungeon->type != LFG_TYPE_DUNGEON && dungeon->type != LFG_TYPE_HEROIC && dungeon->type != LFG_TYPE_RAID)) continue; int botLevel = (int)bot->getLevel(); if (dungeon->minlevel && botLevel < (int)dungeon->minlevel) continue; if (dungeon->minlevel && botLevel > (int)dungeon->minlevel + 10) continue; if (dungeon->maxlevel && botLevel > (int)dungeon->maxlevel) continue; if (heroic && !dungeon->difficulty) continue; if (raid && dungeon->type != LFG_TYPE_RAID) continue; if (random && dungeon->type != LFG_TYPE_RANDOM) continue; if (!random && !raid && !heroic && dungeon->type != LFG_TYPE_DUNGEON) continue; if (!random) list.insert(dungeon->ID); else idx.push_back(dungeon->ID); } if (list.empty()) return false; uint8 roles = GetRoles(); if (random) { list.insert(idx[urand(0, idx.size() - 1)]); sLFGMgr->JoinLfg(bot, roles, list, "bot"); sLog->outMessage("playerbot", LOG_LEVEL_DEBUG, "Bot %s joined to LFG_TYPE_RANDOM as %d", bot->GetName().c_str(), (uint32)roles); return true; } else if (heroic) { sLog->outMessage("playerbot", LOG_LEVEL_DEBUG, "Bot %s joined to LFG_TYPE_HEROIC_DUNGEON as %d", bot->GetName().c_str(), (uint32)roles); } else if (raid) { sLog->outMessage("playerbot", LOG_LEVEL_DEBUG, "Bot %s joined to LFG_TYPE_RAID as %d", bot->GetName().c_str(), (uint32)roles); } else { sLog->outMessage("playerbot", LOG_LEVEL_DEBUG, "Bot %s joined to LFG_TYPE_DUNGEON as %d", bot->GetName().c_str(), (uint32)roles); } sLFGMgr->JoinLfg(bot, roles, list, "bot"); return true; }