Ported .Net Core commits:
hondacrx: - Initial commit: Switch to .Net Core 2.0 - Fix build and removed not needed files Fabi: - Updated solution platforms. - Changed folder structure. - Change library target framework to netstandard2.0. - Updated solution platforms again... - Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 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.Collections.Generic;
|
||||
|
||||
namespace Game.DungeonFinding
|
||||
{
|
||||
public class LFGGroupData
|
||||
{
|
||||
public LFGGroupData()
|
||||
{
|
||||
m_State = LfgState.None;
|
||||
m_OldState = LfgState.None;
|
||||
m_KicksLeft = SharedConst.LFGMaxKicks;
|
||||
}
|
||||
|
||||
public bool IsLfgGroup()
|
||||
{
|
||||
return m_OldState != LfgState.None;
|
||||
}
|
||||
|
||||
public void SetState(LfgState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case LfgState.None:
|
||||
m_Dungeon = 0;
|
||||
m_KicksLeft = SharedConst.LFGMaxKicks;
|
||||
m_OldState = state;
|
||||
break;
|
||||
case LfgState.FinishedDungeon:
|
||||
case LfgState.Dungeon:
|
||||
m_OldState = state;
|
||||
break;
|
||||
}
|
||||
m_State = state;
|
||||
}
|
||||
|
||||
public void RestoreState()
|
||||
{
|
||||
m_State = m_OldState;
|
||||
}
|
||||
|
||||
public void AddPlayer(ObjectGuid guid)
|
||||
{
|
||||
m_Players.Add(guid);
|
||||
}
|
||||
|
||||
public byte RemovePlayer(ObjectGuid guid)
|
||||
{
|
||||
m_Players.Remove(guid);
|
||||
return (byte)m_Players.Count;
|
||||
}
|
||||
|
||||
public void RemoveAllPlayers()
|
||||
{
|
||||
m_Players.Clear();
|
||||
}
|
||||
|
||||
public void SetLeader(ObjectGuid guid)
|
||||
{
|
||||
m_Leader = guid;
|
||||
}
|
||||
|
||||
public void SetDungeon(uint dungeon)
|
||||
{
|
||||
m_Dungeon = dungeon;
|
||||
}
|
||||
|
||||
public void DecreaseKicksLeft()
|
||||
{
|
||||
if (m_KicksLeft != 0)
|
||||
--m_KicksLeft;
|
||||
}
|
||||
|
||||
public LfgState GetState()
|
||||
{
|
||||
return m_State;
|
||||
}
|
||||
|
||||
public LfgState GetOldState()
|
||||
{
|
||||
return m_OldState;
|
||||
}
|
||||
|
||||
public List<ObjectGuid> GetPlayers()
|
||||
{
|
||||
return m_Players;
|
||||
}
|
||||
|
||||
public byte GetPlayerCount()
|
||||
{
|
||||
return (byte)m_Players.Count;
|
||||
}
|
||||
|
||||
public ObjectGuid GetLeader()
|
||||
{
|
||||
return m_Leader;
|
||||
}
|
||||
|
||||
public uint GetDungeon(bool asId = true)
|
||||
{
|
||||
if (asId)
|
||||
return (m_Dungeon & 0x00FFFFFF);
|
||||
else
|
||||
return m_Dungeon;
|
||||
}
|
||||
|
||||
public byte GetKicksLeft()
|
||||
{
|
||||
return m_KicksLeft;
|
||||
}
|
||||
|
||||
public void SetVoteKick(bool active)
|
||||
{
|
||||
m_VoteKickActive = active;
|
||||
}
|
||||
|
||||
public bool IsVoteKickActive()
|
||||
{
|
||||
return m_VoteKickActive;
|
||||
}
|
||||
|
||||
// General
|
||||
LfgState m_State;
|
||||
LfgState m_OldState;
|
||||
ObjectGuid m_Leader;
|
||||
List<ObjectGuid> m_Players = new List<ObjectGuid>();
|
||||
// Dungeon
|
||||
uint m_Dungeon;
|
||||
// Vote Kick
|
||||
byte m_KicksLeft;
|
||||
bool m_VoteKickActive;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 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.Collections.Generic;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.DungeonFinding
|
||||
{
|
||||
public class LFGPlayerData
|
||||
{
|
||||
public LFGPlayerData()
|
||||
{
|
||||
m_State = LfgState.None;
|
||||
m_OldState = LfgState.None;
|
||||
}
|
||||
|
||||
public void SetTicket(RideTicket ticket)
|
||||
{
|
||||
m_Ticket = ticket;
|
||||
}
|
||||
|
||||
public void SetState(LfgState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case LfgState.None:
|
||||
case LfgState.FinishedDungeon:
|
||||
m_Roles = 0;
|
||||
m_SelectedDungeons.Clear();
|
||||
goto case LfgState.Dungeon;
|
||||
case LfgState.Dungeon:
|
||||
m_OldState = state;
|
||||
break;
|
||||
}
|
||||
m_State = state;
|
||||
}
|
||||
|
||||
public void RestoreState()
|
||||
{
|
||||
if (m_OldState == LfgState.None)
|
||||
{
|
||||
m_SelectedDungeons.Clear();
|
||||
m_Roles = 0;
|
||||
}
|
||||
m_State = m_OldState;
|
||||
}
|
||||
|
||||
public void SetTeam(Team team)
|
||||
{
|
||||
m_Team = team;
|
||||
}
|
||||
|
||||
public void SetGroup(ObjectGuid group)
|
||||
{
|
||||
m_Group = group;
|
||||
}
|
||||
|
||||
public void SetRoles(LfgRoles roles)
|
||||
{
|
||||
m_Roles = roles;
|
||||
}
|
||||
|
||||
public void SetSelectedDungeons(List<uint> dungeons)
|
||||
{
|
||||
m_SelectedDungeons = dungeons;
|
||||
}
|
||||
|
||||
public RideTicket GetTicket()
|
||||
{
|
||||
return m_Ticket;
|
||||
}
|
||||
|
||||
public LfgState GetState()
|
||||
{
|
||||
return m_State;
|
||||
}
|
||||
|
||||
public LfgState GetOldState()
|
||||
{
|
||||
return m_OldState;
|
||||
}
|
||||
|
||||
public Team GetTeam()
|
||||
{
|
||||
return m_Team;
|
||||
}
|
||||
|
||||
public ObjectGuid GetGroup()
|
||||
{
|
||||
return m_Group;
|
||||
}
|
||||
|
||||
public LfgRoles GetRoles()
|
||||
{
|
||||
return m_Roles;
|
||||
}
|
||||
|
||||
public List<uint> GetSelectedDungeons()
|
||||
{
|
||||
return m_SelectedDungeons;
|
||||
}
|
||||
|
||||
// General
|
||||
RideTicket m_Ticket;
|
||||
LfgState m_State;
|
||||
LfgState m_OldState;
|
||||
// Player
|
||||
Team m_Team;
|
||||
ObjectGuid m_Group;
|
||||
|
||||
// Queue
|
||||
LfgRoles m_Roles;
|
||||
List<uint> m_SelectedDungeons = new List<uint>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,780 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 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 string.Format("Queued Players: {0} (in group: {1}) Groups: {2}\n", players, playersInGroup, groups);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 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 Game.Groups;
|
||||
using Game.Maps;
|
||||
using Game.Scripting;
|
||||
|
||||
namespace Game.DungeonFinding
|
||||
{
|
||||
class LFGPlayerScript : PlayerScript
|
||||
{
|
||||
public LFGPlayerScript() : base("LFGPlayerScript") { }
|
||||
|
||||
// Player Hooks
|
||||
public override void OnLogout(Player player)
|
||||
{
|
||||
if (!Global.LFGMgr.isOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser))
|
||||
return;
|
||||
|
||||
if (!player.GetGroup())
|
||||
Global.LFGMgr.LeaveLfg(player.GetGUID());
|
||||
else if (player.GetSession().PlayerDisconnected())
|
||||
Global.LFGMgr.LeaveLfg(player.GetGUID(), true);
|
||||
}
|
||||
|
||||
public override void OnLogin(Player player)
|
||||
{
|
||||
if (!Global.LFGMgr.isOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser))
|
||||
return;
|
||||
|
||||
// Temporal: Trying to determine when group data and LFG data gets desynched
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
ObjectGuid gguid = Global.LFGMgr.GetGroup(guid);
|
||||
|
||||
Group group = player.GetGroup();
|
||||
if (group)
|
||||
{
|
||||
ObjectGuid gguid2 = group.GetGUID();
|
||||
if (gguid != gguid2)
|
||||
{
|
||||
Log.outError(LogFilter.Lfg, "{0} on group {1} but LFG has group {2} saved... Fixing.", player.GetSession().GetPlayerInfo(), gguid2.ToString(), gguid.ToString());
|
||||
Global.LFGMgr.SetupGroupMember(guid, group.GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
Global.LFGMgr.SetTeam(player.GetGUID(), player.GetTeam());
|
||||
/// @todo - Restore LfgPlayerData and send proper status to player if it was in a group
|
||||
}
|
||||
|
||||
public override void OnMapChanged(Player player)
|
||||
{
|
||||
Map map = player.GetMap();
|
||||
|
||||
if (Global.LFGMgr.inLfgDungeonMap(player.GetGUID(), map.GetId(), map.GetDifficultyID()))
|
||||
{
|
||||
Group group = player.GetGroup();
|
||||
// This function is also called when players log in
|
||||
// if for some reason the LFG system recognises the player as being in a LFG dungeon,
|
||||
// but the player was loaded without a valid group, we'll teleport to homebind to prevent
|
||||
// crashes or other undefined behaviour
|
||||
if (!group)
|
||||
{
|
||||
Global.LFGMgr.LeaveLfg(player.GetGUID());
|
||||
player.RemoveAurasDueToSpell(SharedConst.LFGSpellLuckOfTheDraw);
|
||||
player.TeleportTo(player.GetHomebind());
|
||||
Log.outError(LogFilter.Lfg, "LFGPlayerScript.OnMapChanged, Player {0} ({1}) is in LFG dungeon map but does not have a valid group! Teleporting to homebind.",
|
||||
player.GetName(), player.GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player member = refe.GetSource();
|
||||
if (member)
|
||||
player.GetSession().SendNameQuery(member.GetGUID());
|
||||
}
|
||||
|
||||
if (Global.LFGMgr.selectedRandomLfgDungeon(player.GetGUID()))
|
||||
player.CastSpell(player, SharedConst.LFGSpellLuckOfTheDraw, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Group group = player.GetGroup();
|
||||
if (group && group.GetMembersCount() == 1)
|
||||
{
|
||||
Global.LFGMgr.LeaveLfg(group.GetGUID());
|
||||
group.Disband();
|
||||
Log.outDebug(LogFilter.Lfg, "LFGPlayerScript::OnMapChanged, Player {0}({1}) is last in the lfggroup so we disband the group.",
|
||||
player.GetName(), player.GetGUID().ToString());
|
||||
}
|
||||
|
||||
player.RemoveAurasDueToSpell(SharedConst.LFGSpellLuckOfTheDraw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LFGGroupScript : GroupScript
|
||||
{
|
||||
public LFGGroupScript() : base("LFGGroupScript") { }
|
||||
|
||||
// Group Hooks
|
||||
public override void OnAddMember(Group group, ObjectGuid guid)
|
||||
{
|
||||
if (!Global.LFGMgr.isOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser))
|
||||
return;
|
||||
|
||||
ObjectGuid gguid = group.GetGUID();
|
||||
ObjectGuid leader = group.GetLeaderGUID();
|
||||
|
||||
if (leader == guid)
|
||||
{
|
||||
Log.outDebug(LogFilter.Lfg, "LFGScripts.OnAddMember [{0}]: added [{1} leader {2}]", gguid, guid, leader);
|
||||
Global.LFGMgr.SetLeader(gguid, guid);
|
||||
}
|
||||
else
|
||||
{
|
||||
LfgState gstate = Global.LFGMgr.GetState(gguid);
|
||||
LfgState state = Global.LFGMgr.GetState(guid);
|
||||
Log.outDebug(LogFilter.Lfg, "LFGScripts.OnAddMember [{0}]: added [{1} leader {2}] gstate: {3}, state: {4}", gguid, guid, leader, gstate, state);
|
||||
|
||||
if (state == LfgState.Queued)
|
||||
Global.LFGMgr.LeaveLfg(guid);
|
||||
|
||||
if (gstate == LfgState.Queued)
|
||||
Global.LFGMgr.LeaveLfg(gguid);
|
||||
}
|
||||
|
||||
Global.LFGMgr.SetGroup(guid, gguid);
|
||||
Global.LFGMgr.AddPlayerToGroup(gguid, guid);
|
||||
}
|
||||
|
||||
public override void OnRemoveMember(Group group, ObjectGuid guid, RemoveMethod method, ObjectGuid kicker, string reason)
|
||||
{
|
||||
if (!Global.LFGMgr.isOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser))
|
||||
return;
|
||||
|
||||
ObjectGuid gguid = group.GetGUID();
|
||||
Log.outDebug(LogFilter.Lfg, "LFGScripts.OnRemoveMember [{0}]: remove [{1}] Method: {2} Kicker: {3} Reason: {4}", gguid, guid, method, kicker, reason);
|
||||
|
||||
bool isLFG = group.isLFGGroup();
|
||||
|
||||
if (isLFG && method == RemoveMethod.Kick) // Player have been kicked
|
||||
{
|
||||
/// @todo - Update internal kick cooldown of kicker
|
||||
string str_reason = "";
|
||||
if (!string.IsNullOrEmpty(reason))
|
||||
str_reason = reason;
|
||||
Global.LFGMgr.InitBoot(gguid, kicker, guid, str_reason);
|
||||
return;
|
||||
}
|
||||
|
||||
LfgState state = Global.LFGMgr.GetState(gguid);
|
||||
|
||||
// If group is being formed after proposal success do nothing more
|
||||
if (state == LfgState.Proposal && method == RemoveMethod.Default)
|
||||
{
|
||||
// LfgData: Remove player from group
|
||||
Global.LFGMgr.SetGroup(guid, ObjectGuid.Empty);
|
||||
Global.LFGMgr.RemovePlayerFromGroup(gguid, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
Global.LFGMgr.LeaveLfg(guid);
|
||||
Global.LFGMgr.SetGroup(guid, ObjectGuid.Empty);
|
||||
byte players = Global.LFGMgr.RemovePlayerFromGroup(gguid, guid);
|
||||
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (player)
|
||||
{
|
||||
if (method == RemoveMethod.Leave && state == LfgState.Dungeon &&
|
||||
players >= SharedConst.LFGKickVotesNeeded)
|
||||
player.CastSpell(player, SharedConst.LFGSpellDungeonDeserter, true);
|
||||
//else if (state == LFG_STATE_BOOT)
|
||||
// Update internal kick cooldown of kicked
|
||||
|
||||
player.GetSession().SendLfgUpdateStatus(new LfgUpdateData(LfgUpdateType.LeaderUnk1), true);
|
||||
if (isLFG && player.GetMap().IsDungeon()) // Teleport player out the dungeon
|
||||
Global.LFGMgr.TeleportPlayer(player, true);
|
||||
}
|
||||
|
||||
if (isLFG && state != LfgState.FinishedDungeon) // Need more players to finish the dungeon
|
||||
{
|
||||
Player leader = Global.ObjAccessor.FindPlayer(Global.LFGMgr.GetLeader(gguid));
|
||||
if (leader)
|
||||
leader.GetSession().SendLfgOfferContinue(Global.LFGMgr.GetDungeon(gguid, false));
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDisband(Group group)
|
||||
{
|
||||
if (!Global.LFGMgr.isOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser))
|
||||
return;
|
||||
|
||||
ObjectGuid gguid = group.GetGUID();
|
||||
Log.outDebug(LogFilter.Lfg, "LFGScripts.OnDisband {0}", gguid);
|
||||
|
||||
Global.LFGMgr.RemoveGroupData(gguid);
|
||||
}
|
||||
|
||||
public override void OnChangeLeader(Group group, ObjectGuid newLeaderGuid, ObjectGuid oldLeaderGuid)
|
||||
{
|
||||
if (!Global.LFGMgr.isOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser))
|
||||
return;
|
||||
|
||||
ObjectGuid gguid = group.GetGUID();
|
||||
|
||||
Log.outDebug(LogFilter.Lfg, "LFGScripts.OnChangeLeader {0}: old {0} new {0}", gguid, newLeaderGuid, oldLeaderGuid);
|
||||
Global.LFGMgr.SetLeader(gguid, newLeaderGuid);
|
||||
}
|
||||
|
||||
public override void OnInviteMember(Group group, ObjectGuid guid)
|
||||
{
|
||||
if (!Global.LFGMgr.isOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser))
|
||||
return;
|
||||
|
||||
ObjectGuid gguid = group.GetGUID();
|
||||
ObjectGuid leader = group.GetLeaderGUID();
|
||||
Log.outDebug(LogFilter.Lfg, "LFGScripts.OnInviteMember {0}: invite {0} leader {0}", gguid, guid, leader);
|
||||
// No gguid == new group being formed
|
||||
// No leader == after group creation first invite is new leader
|
||||
// leader and no gguid == first invite after leader is added to new group (this is the real invite)
|
||||
if (!leader.IsEmpty() && gguid.IsEmpty())
|
||||
Global.LFGMgr.LeaveLfg(leader);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user