Files
CypherCore/Source/Game/DungeonFinding/LFGQueue.cs
T
2018-05-07 22:07:35 -04:00

781 lines
30 KiB
C#

/*
* Copyright (C) 2012-2018 CypherCore <http://github.com/CypherCore>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Framework.Constants;
using Game.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Game.DungeonFinding
{
public class LFGQueue
{
public static string ConcatenateGuids(List<ObjectGuid> guids)
{
if (guids.Empty())
return "";
// need the guids in order to avoid duplicates
StringBuilder val = new StringBuilder();
guids.Sort();
var it = guids.First();
val.Append(it);
foreach (var guid in guids)
{
if (guid == it)
continue;
val.AppendFormat("|{0}", guid);
}
return val.ToString();
}
public static string GetRolesString(LfgRoles roles)
{
StringBuilder rolesstr = new StringBuilder();
if (roles.HasAnyFlag(LfgRoles.Tank))
rolesstr.Append("Tank");
if (roles.HasAnyFlag(LfgRoles.Healer))
{
if (rolesstr.Capacity != 0)
rolesstr.Append(", ");
rolesstr.Append("Healer");
}
if (roles.HasAnyFlag(LfgRoles.Damage))
{
if (rolesstr.Capacity != 0)
rolesstr.Append(", ");
rolesstr.Append("Damage");
}
if (roles.HasAnyFlag(LfgRoles.Leader))
{
if (rolesstr.Capacity != 0)
rolesstr.Append(", ");
rolesstr.Append("Leader");
}
if (rolesstr.Capacity == 0)
rolesstr.Append("None");
return rolesstr.ToString();
}
public static string ConcatenateDungeons(List<uint> dungeons)
{
string str = "";
if (!dungeons.Empty())
{
foreach (var it in dungeons)
{
if (!string.IsNullOrEmpty(str))
str += ", ";
str += it;
}
}
return str;
}
string GetCompatibleString(LfgCompatibility compatibles)
{
switch (compatibles)
{
case LfgCompatibility.Pending:
return "Pending";
case LfgCompatibility.BadStates:
return "Compatibles (Bad States)";
case LfgCompatibility.Match:
return "Match";
case LfgCompatibility.WithLessPlayers:
return "Compatibles (Not enough players)";
case LfgCompatibility.HasIgnores:
return "Has ignores";
case LfgCompatibility.MultipleLfgGroups:
return "Multiple Lfg Groups";
case LfgCompatibility.NoDungeons:
return "Incompatible dungeons";
case LfgCompatibility.NoRoles:
return "Incompatible roles";
case LfgCompatibility.TooMuchPlayers:
return "Too much players";
case LfgCompatibility.WrongGroupSize:
return "Wrong group size";
default:
return "Unknown";
}
}
public void AddToQueue(ObjectGuid guid, bool reAdd = false)
{
if (!QueueDataStore.ContainsKey(guid))
{
Log.outError(LogFilter.Lfg, "AddToQueue: Queue data not found for [{0}]", guid);
return;
}
if (reAdd)
AddToFrontCurrentQueue(guid);
else
AddToNewQueue(guid);
}
public void RemoveFromQueue(ObjectGuid guid)
{
RemoveFromNewQueue(guid);
RemoveFromCurrentQueue(guid);
RemoveFromCompatibles(guid);
string sguid = guid.ToString();
var itDelete = QueueDataStore.LastOrDefault().Key;
foreach (var key in QueueDataStore.Keys.ToList())
{
var data = QueueDataStore[key];
if (key != guid)
{
if (data.bestCompatible.Contains(sguid))
{
data.bestCompatible = "";
FindBestCompatibleInQueue(key, data);
}
}
else
itDelete = key;
}
if (!itDelete.IsEmpty())
QueueDataStore.Remove(itDelete);
}
public void AddToNewQueue(ObjectGuid guid)
{
newToQueueStore.Add(guid);
}
public void RemoveFromNewQueue(ObjectGuid guid)
{
newToQueueStore.Remove(guid);
}
public void AddToCurrentQueue(ObjectGuid guid)
{
currentQueueStore.Add(guid);
}
void AddToFrontCurrentQueue(ObjectGuid guid)
{
currentQueueStore.Insert(0, guid);
}
public void RemoveFromCurrentQueue(ObjectGuid guid)
{
currentQueueStore.Remove(guid);
}
public void AddQueueData(ObjectGuid guid, long joinTime, List<uint> dungeons, Dictionary<ObjectGuid, LfgRoles> rolesMap)
{
QueueDataStore[guid] = new LfgQueueData(joinTime, dungeons, rolesMap);
AddToQueue(guid);
}
public void RemoveQueueData(ObjectGuid guid)
{
QueueDataStore.Remove(guid);
}
public void UpdateWaitTimeAvg(int waitTime, uint dungeonId)
{
LfgWaitTime wt = waitTimesAvgStore[dungeonId];
uint old_number = wt.number++;
wt.time = (int)((wt.time * old_number + waitTime) / wt.number);
}
public void UpdateWaitTimeTank(int waitTime, uint dungeonId)
{
LfgWaitTime wt = waitTimesTankStore[dungeonId];
uint old_number = wt.number++;
wt.time = (int)((wt.time * old_number + waitTime) / wt.number);
}
public void UpdateWaitTimeHealer(int waitTime, uint dungeonId)
{
LfgWaitTime wt = waitTimesHealerStore[dungeonId];
uint old_number = wt.number++;
wt.time = (int)((wt.time * old_number + waitTime) / wt.number);
}
public void UpdateWaitTimeDps(int waitTime, uint dungeonId)
{
LfgWaitTime wt = waitTimesDpsStore[dungeonId];
uint old_number = wt.number++;
wt.time = (int)((wt.time * old_number + waitTime) / wt.number);
}
void RemoveFromCompatibles(ObjectGuid guid)
{
string strGuid = guid.ToString();
Log.outDebug(LogFilter.Lfg, "RemoveFromCompatibles: Removing [{0}]", guid);
foreach (var itNext in CompatibleMapStore.ToList())
{
if (itNext.Key.Contains(strGuid))
CompatibleMapStore.Remove(itNext.Key);
}
}
void SetCompatibles(string key, LfgCompatibility compatibles)
{
if (!CompatibleMapStore.ContainsKey(key))
CompatibleMapStore[key] = new LfgCompatibilityData();
CompatibleMapStore[key].compatibility = compatibles;
}
void SetCompatibilityData(string key, LfgCompatibilityData data)
{
CompatibleMapStore[key] = data;
}
LfgCompatibility GetCompatibles(string key)
{
var compatibilityData = CompatibleMapStore.LookupByKey(key);
if (compatibilityData != null)
return compatibilityData.compatibility;
return LfgCompatibility.Pending;
}
LfgCompatibilityData GetCompatibilityData(string key)
{
var compatibilityData = CompatibleMapStore.LookupByKey(key);
if (compatibilityData != null)
return compatibilityData;
return null;
}
public byte FindGroups()
{
byte proposals = 0;
List<ObjectGuid> firstNew = new List<ObjectGuid>();
while (!newToQueueStore.Empty())
{
ObjectGuid frontguid = newToQueueStore.First();
Log.outDebug(LogFilter.Lfg, "FindGroups: checking [{0}] newToQueue({1}), currentQueue({2})", frontguid, newToQueueStore.Count, currentQueueStore.Count);
firstNew.Clear();
firstNew.Add(frontguid);
RemoveFromNewQueue(frontguid);
List<ObjectGuid> temporalList = new List<ObjectGuid>(currentQueueStore);
LfgCompatibility compatibles = FindNewGroups(firstNew, temporalList);
if (compatibles == LfgCompatibility.Match)
++proposals;
else
AddToCurrentQueue(frontguid); // Lfg group not found, add this group to the queue.
}
return proposals;
}
LfgCompatibility FindNewGroups(List<ObjectGuid> check, List<ObjectGuid> all)
{
string strGuids = ConcatenateGuids(check);
LfgCompatibility compatibles = GetCompatibles(strGuids);
Log.outDebug(LogFilter.Lfg, "FindNewGroup: ({0}): {1} - all({2})", strGuids, GetCompatibleString(compatibles), ConcatenateGuids(all));
if (compatibles == LfgCompatibility.Pending) // Not previously cached, calculate
compatibles = CheckCompatibility(check);
if (compatibles == LfgCompatibility.BadStates && Global.LFGMgr.AllQueued(check))
{
Log.outDebug(LogFilter.Lfg, "FindNewGroup: ({0}) compatibles (cached) changed from bad states to match", strGuids);
SetCompatibles(strGuids, LfgCompatibility.Match);
return LfgCompatibility.Match;
}
if (compatibles != LfgCompatibility.WithLessPlayers)
return compatibles;
// Try to match with queued groups
while (!all.Empty())
{
check.Add(all.First());
all.RemoveAt(0);
LfgCompatibility subcompatibility = FindNewGroups(check, all);
if (subcompatibility == LfgCompatibility.Match)
return LfgCompatibility.Match;
check.RemoveAt(check.Count - 1);
}
return compatibles;
}
LfgCompatibility CheckCompatibility(List<ObjectGuid> check)
{
string strGuids = ConcatenateGuids(check);
LfgProposal proposal = new LfgProposal();
List<uint> proposalDungeons;
Dictionary<ObjectGuid, ObjectGuid> proposalGroups = new Dictionary<ObjectGuid, ObjectGuid>();
Dictionary<ObjectGuid, LfgRoles> proposalRoles = new Dictionary<ObjectGuid, LfgRoles>();
// Check for correct size
if (check.Count > MapConst.MaxGroupSize || check.Empty())
{
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}): Size wrong - Not compatibles", strGuids);
return LfgCompatibility.WrongGroupSize;
}
// Check all-but-new compatiblitity
if (check.Count > 2)
{
ObjectGuid frontGuid = check.First();
check.RemoveAt(0);
// Check all-but-new compatibilities (New, A, B, C, D) -. check(A, B, C, D)
LfgCompatibility child_compatibles = CheckCompatibility(check);
if (child_compatibles < LfgCompatibility.WithLessPlayers) // Group not compatible
{
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}) child {1} not compatibles", strGuids, ConcatenateGuids(check));
SetCompatibles(strGuids, child_compatibles);
return child_compatibles;
}
check.Insert(0, frontGuid);
}
// Check if more than one LFG group and number of players joining
byte numPlayers = 0;
byte numLfgGroups = 0;
foreach (var guid in check)
{
if (!(numLfgGroups < 2) && !(numPlayers <= MapConst.MaxGroupSize))
break;
var itQueue = QueueDataStore.LookupByKey(guid);
if (itQueue == null)
{
Log.outError(LogFilter.Lfg, "CheckCompatibility: [{0}] is not queued but listed as queued!", guid);
RemoveFromQueue(guid);
return LfgCompatibility.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)
foreach (var it2 in itQueue.roles)
proposalGroups[it2.Key] = guid.IsPlayer() ? guid : ObjectGuid.Empty;
numPlayers += (byte)itQueue.roles.Count;
if (Global.LFGMgr.IsLfgGroup(guid))
{
if (numLfgGroups == 0)
proposal.group = guid;
++numLfgGroups;
}
}
// Group with less that MAXGROUPSIZE members always compatible
if (check.Count == 1 && numPlayers != MapConst.MaxGroupSize)
{
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}) sigle group. Compatibles", strGuids);
var guid = check.First();
var itQueue = QueueDataStore.LookupByKey(guid);
LfgCompatibilityData data = new LfgCompatibilityData(LfgCompatibility.WithLessPlayers);
data.roles = itQueue.roles;
Global.LFGMgr.CheckGroupRoles(data.roles);
UpdateBestCompatibleInQueue(guid, itQueue, strGuids, data.roles);
SetCompatibilityData(strGuids, data);
return LfgCompatibility.WithLessPlayers;
}
if (numLfgGroups > 1)
{
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}) More than one Lfggroup ({1})", strGuids, numLfgGroups);
SetCompatibles(strGuids, LfgCompatibility.MultipleLfgGroups);
return LfgCompatibility.MultipleLfgGroups;
}
if (numPlayers > MapConst.MaxGroupSize)
{
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}) Too much players ({1})", strGuids, numPlayers);
SetCompatibles(strGuids, LfgCompatibility.TooMuchPlayers);
return LfgCompatibility.TooMuchPlayers;
}
// 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.Count > 1)
{
foreach (var it in check)
{
Dictionary<ObjectGuid, LfgRoles> roles = QueueDataStore[it].roles;
foreach (var rolePair in roles)
{
KeyValuePair<ObjectGuid, LfgRoles> itPlayer = new KeyValuePair<ObjectGuid, LfgRoles>();
foreach (var _player in proposalRoles)
{
itPlayer = _player;
if (rolePair.Key == itPlayer.Key)
Log.outError(LogFilter.Lfg, "CheckCompatibility: ERROR! Player multiple times in queue! [{0}]", rolePair.Key);
else if (Global.LFGMgr.HasIgnore(rolePair.Key, itPlayer.Key))
break;
}
if (itPlayer.Key == proposalRoles.LastOrDefault().Key)
proposalRoles[rolePair.Key] = rolePair.Value;
}
}
byte playersize = (byte)(numPlayers - proposalRoles.Count);
if (playersize != 0)
{
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}) not compatible, {1} players are ignoring each other", strGuids, playersize);
SetCompatibles(strGuids, LfgCompatibility.HasIgnores);
return LfgCompatibility.HasIgnores;
}
StringBuilder o;
Dictionary<ObjectGuid, LfgRoles> debugRoles = proposalRoles;
if (!Global.LFGMgr.CheckGroupRoles(proposalRoles))
{
o = new StringBuilder();
foreach (var it in debugRoles)
o.AppendFormat(", {0}: {1}", it.Key, GetRolesString(it.Value));
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}) Roles not compatible{1}", strGuids, o.ToString());
SetCompatibles(strGuids, LfgCompatibility.NoRoles);
return LfgCompatibility.NoRoles;
}
var itguid = check.First();
proposalDungeons = QueueDataStore[itguid].dungeons;
o = new StringBuilder();
o.AppendFormat(", {0}: ({1})", itguid, Global.LFGMgr.ConcatenateDungeons(proposalDungeons));
foreach (var guid in check)
{
if (guid == itguid)
continue;
List<uint> temporal;
List<uint> dungeons = QueueDataStore[itguid].dungeons;
o.AppendFormat(", {0}: ({1})", guid, Global.LFGMgr.ConcatenateDungeons(dungeons));
temporal = proposalDungeons.Intersect(dungeons).ToList();
proposalDungeons = temporal;
}
if (proposalDungeons.Empty())
{
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}) No compatible dungeons{1}", strGuids, o.ToString());
SetCompatibles(strGuids, LfgCompatibility.NoDungeons);
return LfgCompatibility.NoDungeons;
}
}
else
{
ObjectGuid gguid = check.First();
LfgQueueData queue = QueueDataStore[gguid];
proposalDungeons = queue.dungeons;
proposalRoles = queue.roles;
Global.LFGMgr.CheckGroupRoles(proposalRoles); // assing new roles
}
// Enough players?
if (numPlayers != MapConst.MaxGroupSize)
{
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}) Compatibles but not enough players({1})", strGuids, numPlayers);
LfgCompatibilityData data = new LfgCompatibilityData(LfgCompatibility.WithLessPlayers);
data.roles = proposalRoles;
foreach (var guid in check)
{
var queueData = QueueDataStore.LookupByKey(guid);
UpdateBestCompatibleInQueue(guid, queueData, strGuids, data.roles);
}
SetCompatibilityData(strGuids, data);
return LfgCompatibility.WithLessPlayers;
}
ObjectGuid _guid = check.First();
proposal.queues = check;
proposal.isNew = numLfgGroups != 1 || Global.LFGMgr.GetOldState(_guid) != LfgState.Dungeon;
if (!Global.LFGMgr.AllQueued(check))
{
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}) Group MATCH but can't create proposal!", strGuids);
SetCompatibles(strGuids, LfgCompatibility.BadStates);
return LfgCompatibility.BadStates;
}
// Create a new proposal
proposal.cancelTime = Time.UnixTime + SharedConst.LFGTimeProposal;
proposal.state = LfgProposalState.Initiating;
proposal.leader = ObjectGuid.Empty;
proposal.dungeonId = proposalDungeons.SelectRandom();
bool leader = false;
foreach (var rolePair in proposalRoles)
{
// Assing new leader
if (rolePair.Value.HasAnyFlag(LfgRoles.Leader))
{
if (!leader || proposal.leader.IsEmpty() || Convert.ToBoolean(RandomHelper.IRand(0, 1)))
proposal.leader = rolePair.Key;
leader = true;
}
else if (!leader && (proposal.leader.IsEmpty() || Convert.ToBoolean(RandomHelper.IRand(0, 1))))
proposal.leader = rolePair.Key;
// Assing player data and roles
LfgProposalPlayer data = new LfgProposalPlayer();
data.role = rolePair.Value;
data.group = proposalGroups.LookupByKey(rolePair.Key);
if (!proposal.isNew && !data.group.IsEmpty() && data.group == proposal.group) // Player from existing group, autoaccept
data.accept = LfgAnswer.Agree;
proposal.players[rolePair.Key] = data;
}
// Mark proposal members as not queued (but not remove queue data)
foreach (var guid in proposal.queues)
{
RemoveFromNewQueue(guid);
RemoveFromCurrentQueue(guid);
}
Global.LFGMgr.AddProposal(proposal);
Log.outDebug(LogFilter.Lfg, "CheckCompatibility: ({0}) MATCH! Group formed", strGuids);
SetCompatibles(strGuids, LfgCompatibility.Match);
return LfgCompatibility.Match;
}
public void UpdateQueueTimers(byte queueId, long currTime)
{
Log.outDebug(LogFilter.Lfg, "Updating queue timers...");
foreach (var itQueue in QueueDataStore)
{
LfgQueueData queueinfo = itQueue.Value;
uint dungeonId = queueinfo.dungeons.FirstOrDefault();
uint queuedTime = (uint)(currTime - queueinfo.joinTime);
LfgRoles role = LfgRoles.None;
int waitTime = -1;
if (!waitTimesTankStore.ContainsKey(dungeonId))
waitTimesTankStore[dungeonId] = new LfgWaitTime();
if (!waitTimesHealerStore.ContainsKey(dungeonId))
waitTimesHealerStore[dungeonId] = new LfgWaitTime();
if (!waitTimesDpsStore.ContainsKey(dungeonId))
waitTimesDpsStore[dungeonId] = new LfgWaitTime();
if (!waitTimesAvgStore.ContainsKey(dungeonId))
waitTimesAvgStore[dungeonId] = new LfgWaitTime();
int wtTank = waitTimesTankStore[dungeonId].time;
int wtHealer = waitTimesHealerStore[dungeonId].time;
int wtDps = waitTimesDpsStore[dungeonId].time;
int wtAvg = waitTimesAvgStore[dungeonId].time;
foreach (var itPlayer in queueinfo.roles)
role |= itPlayer.Value;
role &= ~LfgRoles.Leader;
switch (role)
{
case LfgRoles.None: // Should not happen - just in case
waitTime = -1;
break;
case LfgRoles.Tank:
waitTime = wtTank;
break;
case LfgRoles.Healer:
waitTime = wtHealer;
break;
case LfgRoles.Damage:
waitTime = wtDps;
break;
default:
waitTime = wtAvg;
break;
}
if (string.IsNullOrEmpty(queueinfo.bestCompatible))
FindBestCompatibleInQueue(itQueue.Key, itQueue.Value);
LfgQueueStatusData queueData = new LfgQueueStatusData(queueId, dungeonId, waitTime, wtAvg, wtTank, wtHealer, wtDps, queuedTime, queueinfo.tanks, queueinfo.healers, queueinfo.dps);
foreach (var itPlayer in queueinfo.roles)
{
ObjectGuid pguid = itPlayer.Key;
Global.LFGMgr.SendLfgQueueStatus(pguid, queueData);
}
}
}
public long GetJoinTime(ObjectGuid guid)
{
var queueData = QueueDataStore.LookupByKey(guid);
if (queueData != null)
return queueData.joinTime;
return 0;
}
public string DumpQueueInfo()
{
uint players = 0;
uint groups = 0;
uint playersInGroup = 0;
for (byte i = 0; i < 2; ++i)
{
List<ObjectGuid> queue = i != 0 ? newToQueueStore : currentQueueStore;
foreach (var guid in queue)
{
if (guid.IsParty())
{
groups++;
playersInGroup += Global.LFGMgr.GetPlayerCount(guid);
}
else
players++;
}
}
return $"Queued Players: {players} (in group: {playersInGroup}) Groups: {groups}\n";
}
public string DumpCompatibleInfo(bool full = false)
{
string str = "Compatible Map size: " + CompatibleMapStore.Count + "\n";
if (full)
{
foreach (var pair in CompatibleMapStore)
str += "(" + pair.Key + "): " + GetCompatibleString(pair.Value.compatibility) + "\n";
}
return str;
}
void FindBestCompatibleInQueue(ObjectGuid guid, LfgQueueData data)
{
Log.outDebug(LogFilter.Lfg, "FindBestCompatibleInQueue: {0}", guid);
foreach (var pair in CompatibleMapStore)
{
if (pair.Value.compatibility == LfgCompatibility.WithLessPlayers && pair.Key.Contains(guid.ToString()))
UpdateBestCompatibleInQueue(guid, data, pair.Key, pair.Value.roles);
}
}
public void UpdateBestCompatibleInQueue(ObjectGuid guid, LfgQueueData queueData, string key, Dictionary<ObjectGuid, LfgRoles> roles)
{
byte storedSize = (byte)(string.IsNullOrEmpty(queueData.bestCompatible) ? 0 : queueData.bestCompatible.Count(p => p == '|') + 1);
byte size = (byte)(key.Count(p => p == '|') + 1);
if (size <= storedSize)
return;
Log.outDebug(LogFilter.Lfg, "UpdateBestCompatibleInQueue: Changed ({0}) to ({1}) as best compatible group for {2}",
queueData.bestCompatible, key, guid);
queueData.bestCompatible = key;
queueData.tanks = SharedConst.LFGTanksNeeded;
queueData.healers = SharedConst.LFGHealersNeeded;
queueData.dps = SharedConst.LFGDPSNeeded;
foreach (var it in roles)
{
LfgRoles role = it.Value;
if (role.HasAnyFlag(LfgRoles.Tank))
--queueData.tanks;
else if (role.HasAnyFlag(LfgRoles.Healer))
--queueData.healers;
else
--queueData.dps;
}
}
// Queue
Dictionary<ObjectGuid, LfgQueueData> QueueDataStore = new Dictionary<ObjectGuid, LfgQueueData>();
Dictionary<string, LfgCompatibilityData> CompatibleMapStore = new Dictionary<string, LfgCompatibilityData>();
Dictionary<uint, LfgWaitTime> waitTimesAvgStore = new Dictionary<uint, LfgWaitTime>();
Dictionary<uint, LfgWaitTime> waitTimesTankStore = new Dictionary<uint, LfgWaitTime>();
Dictionary<uint, LfgWaitTime> waitTimesHealerStore = new Dictionary<uint, LfgWaitTime>();
Dictionary<uint, LfgWaitTime> waitTimesDpsStore = new Dictionary<uint, LfgWaitTime>();
List<ObjectGuid> currentQueueStore = new List<ObjectGuid>();
List<ObjectGuid> newToQueueStore = new List<ObjectGuid>();
}
public class LfgCompatibilityData
{
public LfgCompatibilityData()
{
compatibility = LfgCompatibility.Pending;
}
public LfgCompatibilityData(LfgCompatibility _compatibility)
{
compatibility = _compatibility;
}
public LfgCompatibilityData(LfgCompatibility _compatibility, Dictionary<ObjectGuid, LfgRoles> _roles)
{
compatibility = _compatibility;
roles = _roles;
}
public LfgCompatibility compatibility;
public Dictionary<ObjectGuid, LfgRoles> roles;
}
// Stores player or group queue info
public class LfgQueueData
{
public LfgQueueData()
{
joinTime = Time.UnixTime;
tanks = SharedConst.LFGTanksNeeded;
healers = SharedConst.LFGHealersNeeded;
dps = SharedConst.LFGDPSNeeded;
}
public LfgQueueData(long _joinTime, List<uint> _dungeons, Dictionary<ObjectGuid, LfgRoles> _roles)
{
joinTime = _joinTime;
tanks = SharedConst.LFGTanksNeeded;
healers = SharedConst.LFGHealersNeeded;
dps = SharedConst.LFGDPSNeeded;
dungeons = _dungeons;
roles = _roles;
}
public long joinTime;
public byte tanks;
public byte healers;
public byte dps;
public List<uint> dungeons;
public Dictionary<ObjectGuid, LfgRoles> roles;
public string bestCompatible = "";
}
public struct LfgWaitTime
{
public int time;
public uint number;
}
}