aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.cpp333
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.h12
2 files changed, 278 insertions, 67 deletions
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp
index cbcfa2253c8..28fe114d058 100644
--- a/src/server/game/DungeonFinding/LFGMgr.cpp
+++ b/src/server/game/DungeonFinding/LFGMgr.cpp
@@ -70,6 +70,8 @@ LFGMgr::~LFGMgr()
for (LfgDungeonMap::iterator it = m_CachedDungeonMap.begin(); it != m_CachedDungeonMap.end(); ++it)
delete it->second;
m_CachedDungeonMap.clear();
+
+ m_CompatibleMap.clear();
m_QueueInfoMap.clear();
m_currentQueue.clear();
m_newToQueue.clear();
@@ -343,10 +345,14 @@ void LFGMgr::Update(uint32 diff)
// Check if a proposal can be formed with the new groups being added
LfgProposalList proposals;
LfgGuidList firstNew;
- if (!m_newToQueue.empty())
+ while (!m_newToQueue.empty())
{
firstNew.push_back(m_newToQueue.front());
- FindNewGroups(firstNew, m_currentQueue, &proposals);
+ if (IS_GROUP(firstNew.front()))
+ CheckCompatibility(firstNew, &proposals); // Check if the group itself match
+ if (!proposals.size())
+ FindNewGroups(firstNew, m_currentQueue, &proposals);
+
if (proposals.size()) // Group found!
{
LfgProposal *pProposal = *proposals.begin();
@@ -538,6 +544,8 @@ bool LFGMgr::RemoveFromQueue(uint64 guid)
m_currentQueue.remove(guid);
m_newToQueue.remove(guid);
+ RemoveFromCompatibles(guid);
+
LfgQueueInfoMap::iterator it = m_QueueInfoMap.find(guid);
if (it != m_QueueInfoMap.end())
{
@@ -727,9 +735,47 @@ void LFGMgr::OfferContinue(Group *grp)
/// <param name="LfgProposalList *">Proposals found.</param>
void LFGMgr::FindNewGroups(LfgGuidList &check, LfgGuidList all, LfgProposalList *proposals)
{
+ ASSERT(proposals);
if (!check.size() || check.size() > MAXGROUPSIZE)
return;
+ sLog.outDebug("LFGMgr::FindNewGroup: (%s) - all(%s)", ConcatenateGuids(check).c_str(), ConcatenateGuids(all).c_str());
+ LfgGuidList compatibles;
+ // Check individual compatibilities
+ for (LfgGuidList::iterator it = all.begin(); it != all.end(); ++it)
+ {
+ check.push_back(*it);
+ if (CheckCompatibility(check, proposals))
+ compatibles.push_back(*it);
+ check.pop_back();
+ }
+
+ while (compatibles.size() > 1)
+ {
+ check.push_back(compatibles.front());
+ compatibles.pop_front();
+ FindNewGroups(check, compatibles, proposals);
+ check.pop_back();
+ }
+}
+
+/// <summary>
+/// Check compatibilities between groups.
+/// </summary>
+/// <param name="LfgGuidList &">Guids we checking compatibility</param>
+/// <returns>bool</returns>
+/// <param name="LfgProposalList *">Proposals found.</param>
+bool LFGMgr::CheckCompatibility(LfgGuidList check, LfgProposalList *proposals)
+{
+ std::string strGuids = ConcatenateGuids(check);
+
+ if (check.size() > MAXGROUPSIZE || !check.size())
+ {
+ sLog.outDebug("LFGMgr::CheckCompatibility: (%s): Size wrong - Not compatibles", strGuids.c_str());
+ return false;
+ }
+
+ // No previous check have been done, do it now
uint8 numPlayers = 0;
uint8 numLfgGroups = 0;
uint32 groupLowGuid = 0;
@@ -740,8 +786,8 @@ void LFGMgr::FindNewGroups(LfgGuidList &check, LfgGuidList all, LfgProposalList
itQueue = m_QueueInfoMap.find(*it);
if (itQueue == m_QueueInfoMap.end())
{
- sLog.outError("LFGMgr::FindNewGroups: " UI64FMTD " is not queued but listed as queued!", *it);
- return;
+ sLog.outError("LFGMgr::CheckCompatibility: " UI64FMTD " is not queued but listed as queued!", *it);
+ return false;
}
pqInfoMap[*it] = itQueue->second;
numPlayers += itQueue->second->roles.size();
@@ -759,24 +805,49 @@ void LFGMgr::FindNewGroups(LfgGuidList &check, LfgGuidList all, LfgProposalList
}
}
- // Do not match groups already in a lfgDungeon
- if (numLfgGroups > 1 || numPlayers > MAXGROUPSIZE)
- {
- pqInfoMap.clear();
- return;
- }
+ if (check.size() == 1 && numPlayers != MAXGROUPSIZE) // Single group with less than MAXGROUPSIZE - Compatibles
+ return true;
- if (numPlayers < MAXGROUPSIZE)
+ if (check.size() > 1)
{
- while (!all.empty() && !proposals->size())
+ // Previously cached?
+ LfgAnswer answer = GetCompatibles(strGuids);
+ if (answer != LFG_ANSWER_PENDING)
{
- check.push_back(all.front());
- all.pop_front();
- FindNewGroups(check, all, proposals);
- check.pop_back();
+ if (numPlayers != MAXGROUPSIZE || answer == LFG_ANSWER_DENY)
+ {
+ sLog.outDebug("LFGMgr::CheckCompatibility: (%s) compatibles (cached): %d", strGuids.c_str(), answer);
+ return bool(answer);
+ }
+ // MAXGROUPSIZE + LFG_ANSWER_AGREE = Match - we don't have it cached so do calcs again
+ }
+ else 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)
+ if (!CheckCompatibility(check, proposals)) // Group not compatible
+ {
+ sLog.outDebug("LFGMgr::CheckCompatibility: (%s) no compatibles (%s not compatibles)", strGuids.c_str(), ConcatenateGuids(check).c_str());
+ SetCompatibles(strGuids, false);
+ return false;
+ }
+ check.push_front(frontGuid);
+ // all-but-new compatibles, now check with new
}
+ }
+
+ // Do not match - groups already in a lfgDungeon or too much players
+ if (numLfgGroups > 1 || numPlayers > MAXGROUPSIZE)
+ {
pqInfoMap.clear();
- return;
+ SetCompatibles(strGuids, false);
+ if (numLfgGroups > 1)
+ sLog.outDebug("LFGMgr::CheckCompatibility: (%s) More than one Lfggroup (%u)", strGuids.c_str(), numLfgGroups);
+ else
+ sLog.outDebug("LFGMgr::CheckCompatibility: (%s) Too much players (%u)", strGuids.c_str(), numPlayers);
+ return false;
}
// ----- Player checks -----
@@ -793,10 +864,12 @@ void LFGMgr::FindNewGroups(LfgGuidList &check, LfgGuidList all, LfgProposalList
}
}
- if (rolesMap.size() != MAXGROUPSIZE)
+ if (rolesMap.size() != numPlayers)
{
- sLog.outError("LFGMgr::FindNewGroups: There is a player multiple times in queue.");
- return;
+ sLog.outError("LFGMgr::CheckCompatibility: There is a player multiple times in queue.");
+ pqInfoMap.clear();
+ rolesMap.clear();
+ return false;
}
Player *plr;
@@ -804,6 +877,9 @@ void LFGMgr::FindNewGroups(LfgGuidList &check, LfgGuidList all, LfgProposalList
for (LfgRolesMap::const_iterator it = rolesMap.begin(); it != rolesMap.end(); ++it)
{
plr = sObjectMgr.GetPlayer(it->first);
+ if (!plr)
+ sLog.outDebug("LFGMgr::CheckCompatibility: (%s) Warning! %u offline!", strGuids.c_str(), it->first);
+
for (PlayerSet::const_iterator itPlayer = players.begin(); itPlayer != players.end() && plr; ++itPlayer)
{
// Do not form a group with ignoring candidates
@@ -817,69 +893,53 @@ void LFGMgr::FindNewGroups(LfgGuidList &check, LfgGuidList all, LfgProposalList
players.insert(plr);
}
- // if we dont have MAXGROUPSIZE (5) then we have self ignoring candidates or different faction groups
+ // if we dont have the same ammount of players then we have self ignoring candidates or different faction groups
// otherwise check if roles are compatible
- if (players.size() != MAXGROUPSIZE || !CheckGroupRoles(rolesMap))
+ if (players.size() != numPlayers || !CheckGroupRoles(rolesMap))
{
- players.clear();
+ if (players.size() != numPlayers)
+ sLog.outDebug("LFGMgr::CheckCompatibility: (%s) Player offline, ignoring or diff teams", strGuids.c_str());
+ else
+ sLog.outDebug("LFGMgr::CheckCompatibility: (%s) Roles not compatible", strGuids.c_str());
pqInfoMap.clear();
- return;
+ rolesMap.clear();
+ players.clear();
+ SetCompatibles(strGuids, false);
+ return false;
}
// ----- Selected Dungeon checks -----
// Check if there are any compatible dungeon from the selected dungeons
+ LfgDungeonMap dungeonMap;
+ for (LfgQueueInfoMap::const_iterator it = pqInfoMap.begin(); it != pqInfoMap.end(); ++it)
+ dungeonMap[it->first] = &it->second->dungeons;
- LfgDungeonSet *compatibleDungeons = new LfgDungeonSet();
- bool compatibleDungeon;
- LfgQueueInfoMap::const_iterator itFirst = pqInfoMap.begin();
- LfgQueueInfoMap::const_iterator itOther;
- LfgDungeonSet::const_iterator itDungeon;
+ LfgDungeonSet *compatibleDungeons = CheckCompatibleDungeons(&dungeonMap, &players);
+ dungeonMap.clear();
+ pqInfoMap.clear();
+ SetCompatibles(strGuids, true);
- // Get the first group and compare with the others to select all common dungeons
- for (itDungeon = itFirst->second->dungeons.begin(); itDungeon != itFirst->second->dungeons.end(); ++itDungeon)
+ if (!compatibleDungeons || !compatibleDungeons->size())
{
- itOther = itFirst;
- compatibleDungeon = true;
- for (++itOther; itOther != pqInfoMap.end() && compatibleDungeon; ++itOther)
- if (itOther->second->dungeons.find(*itDungeon) == itOther->second->dungeons.end())
- compatibleDungeon = false;
- if (compatibleDungeon)
- compatibleDungeons->insert(*itDungeon);
+ if (compatibleDungeons)
+ delete compatibleDungeons;
+ players.clear();
+ rolesMap.clear();
+ return false;
}
- // now remove those with restrictions
- LfgLockStatusMap *pLockDungeons = GetGroupLockStatusDungeons(&players, compatibleDungeons);
- if (pLockDungeons) // Found dungeons not compatible, remove them from the set
+ // ----- Group is compatible, if we have MAXGROUPSIZE members then match is found
+ if (numPlayers != MAXGROUPSIZE)
{
- LfgLockStatusSet *pLockSet = NULL;
- for (LfgLockStatusMap::const_iterator itLockMap = pLockDungeons->begin(); itLockMap != pLockDungeons->end() && compatibleDungeons->size(); ++itLockMap)
- {
- pLockSet = itLockMap->second;
- for(LfgLockStatusSet::const_iterator itLockSet = pLockSet->begin(); itLockSet != pLockSet->end(); ++itLockSet)
- {
- itDungeon = compatibleDungeons->find((*itLockSet)->dungeon);
- if (itDungeon != compatibleDungeons->end())
- compatibleDungeons->erase(itDungeon);
- }
- pLockSet->clear();
- delete pLockSet;
- }
- pLockDungeons->clear();
- delete pLockDungeons;
- }
-
- pqInfoMap.clear();
- // Any compatible dungeon after checking restrictions?
- if (!compatibleDungeons->size())
- {
- delete compatibleDungeons;
- compatibleDungeons = NULL;
players.clear();
- return;
+ rolesMap.clear();
+ sLog.outDebug("LFGMgr::CheckCompatibility: (%s) Compatibles but not match. Players(%u)", strGuids.c_str(), numPlayers);
+ return true;
}
+ sLog.outDebug("LFGMgr::CheckCompatibility: (%s) MATCH! Group formed", strGuids.c_str());
// Select a random dungeon from the compatible list
- itDungeon = compatibleDungeons->begin();
+ LfgDungeonSet::iterator itDungeon = compatibleDungeons->begin();
uint32 selectedDungeon = urand(0, compatibleDungeons->size() - 1);
while (selectedDungeon > 0)
{
@@ -933,7 +993,10 @@ void LFGMgr::FindNewGroups(LfgGuidList &check, LfgGuidList all, LfgProposalList
if (!proposals)
proposals = new LfgProposalList();
proposals->push_back(pProposal);
+
+ rolesMap.clear();
players.clear();
+ return true;
}
/// <summary>
@@ -1090,6 +1153,117 @@ void LFGMgr::UpdateRoleCheck(Group *grp, Player *plr /* = NULL*/)
}
/// <summary>
+/// Remove from cached compatible dungeons any entry that contains the given guid
+/// </summary>
+/// <param name="uint64">guid to remove from any list</param>
+void LFGMgr::RemoveFromCompatibles(uint64 guid)
+{
+ LfgGuidList lista;
+ lista.push_back(guid);
+ std::string strGuid = ConcatenateGuids(lista);
+ lista.clear();
+
+ LfgCompatibleMap::iterator it;
+ for (LfgCompatibleMap::iterator itNext = m_CompatibleMap.begin(); itNext != m_CompatibleMap.end();)
+ {
+ it = itNext++;
+ if (it->first.find(strGuid) != std::string::npos) // Found, remove it
+ {
+ sLog.outDebug("LFGMgr::RemoveFromCompatibles: Removing " UI64FMTD " from (%s)", guid, it->first.c_str());
+ m_CompatibleMap.erase(it);
+ }
+ }
+}
+
+/// <summary>
+/// Set the compatibility of a list of guids
+/// </summary>
+/// <param name="std::string">list of guids concatenated by |</param>
+/// <param name="bool">compatibles or not</param>
+void LFGMgr::SetCompatibles(std::string key, bool compatibles)
+{
+ sLog.outDebug("SPP:LFGMgr::GetCompatibles: (%s): %d", key.c_str(), LfgAnswer(compatibles));
+ m_CompatibleMap[key] = LfgAnswer(compatibles);
+}
+
+/// <summary>
+/// Get the compatible dungeons between two groups from cache
+/// </summary>
+/// <param name="std::string">list of guids concatenated by |</param>
+/// <returns>LfgAnswer,
+LfgAnswer LFGMgr::GetCompatibles(std::string key)
+{
+ LfgAnswer answer = LFG_ANSWER_PENDING;
+ LfgCompatibleMap::iterator it = m_CompatibleMap.find(key);
+ if (it != m_CompatibleMap.end())
+ answer = it->second;
+
+ sLog.outDebug("SPP:LFGMgr::GetCompatibles: (%s): %d", key.c_str(), answer);
+ return answer;
+}
+
+/// <summary>
+/// Given a list of groups checks the compatible dungeons. If players is not null also check restictions
+/// </summary>
+/// <param name="LfgDungeonMap *">dungeons to check</param>
+/// <param name="PlayerSet *">Players to check restrictions</param>
+/// <returns>LfgDungeonSet*</returns>
+LfgDungeonSet* LFGMgr::CheckCompatibleDungeons(LfgDungeonMap *dungeonsMap, PlayerSet *players)
+{
+ if (!dungeonsMap || dungeonsMap->empty())
+ return NULL;
+
+ LfgDungeonMap::const_iterator itMap = ++dungeonsMap->begin();
+ LfgDungeonSet *compatibleDungeons = new LfgDungeonSet();
+
+ bool compatibleDungeon;
+
+ // Get the first group and compare with the others to select all common dungeons
+ for (LfgDungeonSet::const_iterator itDungeon = dungeonsMap->begin()->second->begin(); itDungeon != dungeonsMap->begin()->second->end(); ++itDungeon)
+ {
+ compatibleDungeon = true;
+ for (LfgDungeonMap::const_iterator it = itMap; it != dungeonsMap->end() && compatibleDungeon; ++it)
+ if (it->second->find(*itDungeon) == it->second->end())
+ compatibleDungeon = false;
+ if (compatibleDungeon)
+ compatibleDungeons->insert(*itDungeon);
+ }
+
+ if (players && !players->empty())
+ {
+ // now remove those with restrictions
+ LfgLockStatusMap *pLockDungeons = GetGroupLockStatusDungeons(players, compatibleDungeons);
+ if (pLockDungeons) // Found dungeons not compatible, remove them from the set
+ {
+ LfgLockStatusSet *pLockSet = NULL;
+ LfgDungeonSet::iterator itDungeon;
+ for (LfgLockStatusMap::const_iterator itLockMap = pLockDungeons->begin(); itLockMap != pLockDungeons->end() && compatibleDungeons->size(); ++itLockMap)
+ {
+ pLockSet = itLockMap->second;
+ for(LfgLockStatusSet::const_iterator itLockSet = pLockSet->begin(); itLockSet != pLockSet->end(); ++itLockSet)
+ {
+ itDungeon = compatibleDungeons->find((*itLockSet)->dungeon);
+ if (itDungeon != compatibleDungeons->end())
+ compatibleDungeons->erase(itDungeon);
+ }
+ pLockSet->clear();
+ delete pLockSet;
+ }
+ pLockDungeons->clear();
+ delete pLockDungeons;
+ }
+ }
+
+ // Any compatible dungeon after checking restrictions?
+ if (!compatibleDungeons->size())
+ {
+ delete compatibleDungeons;
+ compatibleDungeons = NULL;
+ }
+ return compatibleDungeons;
+}
+
+/// <summary>
/// Check if a group can be formed with the given group
/// </summary>
/// <param name="LfgRolesMap &">Roles to check</param>
@@ -1349,6 +1523,7 @@ void LFGMgr::RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType t
if (itQueue != m_QueueInfoMap.end())
m_QueueInfoMap.erase(itQueue);
+ RemoveFromCompatibles(guid);
}
else // Readd to queue
{
@@ -1969,3 +2144,29 @@ bool LFGMgr::isRandomDungeon(uint32 dungeonId)
return dungeon->type == LFG_TYPE_RANDOM;
}
+
+/// <summary>
+/// Given a list of guids returns the concatenation using | as delimiter
+/// </summary>
+/// <param name="LfgGuidList ">list of guids</param>
+/// <returns>std::string</returns>
+std::string LFGMgr::ConcatenateGuids(LfgGuidList check)
+{
+ if (check.empty())
+ return "";
+
+ LfgGuidSet guidSet;
+ while (!check.empty())
+ {
+ guidSet.insert(check.front());
+ check.pop_front();
+ }
+
+ std::ostringstream o;
+ LfgGuidSet::iterator it = guidSet.begin();
+ o << *it;
+ for (++it; it != guidSet.end(); ++it)
+ o << "|" << *it;
+ guidSet.clear();
+ return o.str();
+} \ No newline at end of file
diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h
index dcf2c9389ec..6d0f3174368 100644
--- a/src/server/game/DungeonFinding/LFGMgr.h
+++ b/src/server/game/DungeonFinding/LFGMgr.h
@@ -171,7 +171,7 @@ struct LfgReward
typedef std::map<uint32, uint8> LfgRolesMap;
typedef std::map<uint32, LfgAnswer> LfgAnswerMap;
typedef std::list<uint64> LfgGuidList;
-typedef std::map<uint32, LfgDungeonSet*> LfgDungeonMap;
+typedef std::map<uint64, LfgDungeonSet*> LfgDungeonMap;
// Stores player or group queue info
struct LfgQueueInfo
@@ -249,6 +249,9 @@ typedef std::map<uint32, LfgPlayerBoot*> LfgPlayerBootMap;
typedef std::multimap<uint32, LfgReward const*> LfgRewardMap;
typedef std::pair<LfgRewardMap::const_iterator, LfgRewardMap::const_iterator> LfgRewardMapBounds;
typedef std::list<Player *> LfgPlayerList;
+typedef std::set<uint64> LfgGuidSet;
+typedef std::map<std::string, LfgAnswer> LfgCompatibleMap;
+
class LFGMgr
{
@@ -299,6 +302,12 @@ class LFGMgr
void FindNewGroups(LfgGuidList &check, LfgGuidList all, LfgProposalList *proposals);
bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true);
+ bool CheckCompatibility(LfgGuidList check, LfgProposalList *proposals);
+ LfgDungeonSet* CheckCompatibleDungeons(LfgDungeonMap *dungeonsMap, PlayerSet *players);
+ void SetCompatibles(std::string concatenatedGuids, bool compatibles);
+ LfgAnswer GetCompatibles(std::string concatenatedGuids);
+ void RemoveFromCompatibles(uint64 guid);
+ std::string ConcatenateGuids(LfgGuidList check);
void BuildLfgRoleCheck(WorldPacket &data, LfgRoleCheck *pRoleCheck);
void BuildAvailableRandomDungeonList(WorldPacket &data, Player *plr);
@@ -315,6 +324,7 @@ class LFGMgr
LfgQueueInfoMap m_QueueInfoMap; // Queued groups
LfgGuidList m_currentQueue; // Ordered list. Used to find groups
LfgGuidList m_newToQueue; // New groups to add to queue
+ LfgCompatibleMap m_CompatibleMap; // Compatible dungeons
LfgProposalMap m_Proposals; // Current Proposals
LfgPlayerBootMap m_Boots; // Current player kicks
LfgRoleCheckMap m_RoleChecks; // Current Role checks