public void SendLfgProposalUpdate(LfgProposal proposal) { ObjectGuid playerGuid = GetPlayer().GetGUID(); ObjectGuid guildGuid = proposal.players.LookupByKey(playerGuid).group; bool silent = !proposal.isNew && guildGuid == proposal.group; uint dungeonEntry = proposal.dungeonId; Log.outDebug(LogFilter.Lfg, "SMSG_LFG_PROPOSAL_UPDATE {0} state: {1}", GetPlayerInfo(), proposal.state); // show random dungeon if player selected random dungeon and it's not lfg group if (!silent) { List <uint> playerDungeons = Global.LFGMgr.GetSelectedDungeons(playerGuid); if (!playerDungeons.Contains(proposal.dungeonId)) { dungeonEntry = playerDungeons.First(); } } LFGProposalUpdate lfgProposalUpdate = new LFGProposalUpdate(); RideTicket ticket = Global.LFGMgr.GetTicket(GetPlayer().GetGUID()); if (ticket != null) { lfgProposalUpdate.Ticket = ticket; } lfgProposalUpdate.InstanceID = 0; lfgProposalUpdate.ProposalID = proposal.id; lfgProposalUpdate.Slot = Global.LFGMgr.GetLFGDungeonEntry(dungeonEntry); lfgProposalUpdate.State = (byte)proposal.state; lfgProposalUpdate.CompletedMask = proposal.encounters; lfgProposalUpdate.ValidCompletedMask = true; lfgProposalUpdate.ProposalSilent = silent; lfgProposalUpdate.IsRequeue = !proposal.isNew; foreach (var pair in proposal.players) { var proposalPlayer = new LFGProposalUpdatePlayer(); proposalPlayer.Roles = (uint)pair.Value.role; proposalPlayer.Me = (pair.Key == playerGuid); proposalPlayer.MyParty = !pair.Value.group.IsEmpty() && pair.Value.group == proposal.group; proposalPlayer.SameParty = !pair.Value.group.IsEmpty() && pair.Value.group == guildGuid; proposalPlayer.Responded = (pair.Value.accept != LfgAnswer.Pending); proposalPlayer.Accepted = (pair.Value.accept == LfgAnswer.Agree); lfgProposalUpdate.Players.Add(proposalPlayer); } SendPacket(lfgProposalUpdate); }
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); }