コード例 #1
0
        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;
                }
            }
        }
コード例 #2
0
        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);
                }
            }
        }
コード例 #3
0
        LfgCompatibility CheckCompatibility(List <ObjectGuid> check)
        {
            string      strGuids = ConcatenateGuids(check);
            LfgProposal proposal = new();
            List <uint> proposalDungeons;
            Dictionary <ObjectGuid, ObjectGuid> proposalGroups = new();
            Dictionary <ObjectGuid, LfgRoles>   proposalRoles  = new();

            // 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(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();
                        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> dungeons = QueueDataStore[itguid].dungeons;
                    o.AppendFormat(", {0}: ({1})", guid, Global.LFGMgr.ConcatenateDungeons(dungeons));
                    List <uint> 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(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();
                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);
        }
コード例 #4
0
        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(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);
                }
            }
        }
コード例 #5
0
 public void AddQueueData(ObjectGuid guid, long joinTime, List <uint> dungeons, Dictionary <ObjectGuid, LfgRoles> rolesMap)
 {
     QueueDataStore[guid] = new LfgQueueData(joinTime, dungeons, rolesMap);
     AddToQueue(guid);
 }