Core/Maps: Check group that owns instance (first group to enter a given instance id owns it)
Port From (https://github.com/TrinityCore/TrinityCore/commit/a131542855d23022714a97640be1c8d68a741c31)
This commit is contained in:
@@ -584,44 +584,27 @@ namespace Game.Entities
|
|||||||
|
|
||||||
// non-instances are always valid
|
// non-instances are always valid
|
||||||
Map map = GetMap();
|
Map map = GetMap();
|
||||||
if (!map || !map.IsDungeon())
|
InstanceMap instance = map?.ToInstanceMap();
|
||||||
|
if (instance == null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
Group group = GetGroup();
|
||||||
// raid instances require the player to be in a raid group to be valid
|
// raid instances require the player to be in a raid group to be valid
|
||||||
if (map.IsRaid() && !WorldConfig.GetBoolValue(WorldCfg.InstanceIgnoreRaid) && (map.GetEntry().Expansion() >= (Expansion)WorldConfig.GetIntValue(WorldCfg.Expansion)))
|
if (map.IsRaid() && !WorldConfig.GetBoolValue(WorldCfg.InstanceIgnoreRaid) && (map.GetEntry().Expansion() >= (Expansion)WorldConfig.GetIntValue(WorldCfg.Expansion)))
|
||||||
if (!GetGroup() || !GetGroup().IsRaidGroup())
|
if (group == null || group.IsRaidGroup())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Group group = GetGroup();
|
|
||||||
if (group)
|
if (group)
|
||||||
{
|
{
|
||||||
// check if player's group is bound to this instance
|
// check if player's group is bound to this instance
|
||||||
InstanceBind bind = group.GetBoundInstance(map.GetDifficultyID(), map.GetId());
|
if (group != instance.GetOwningGroup())
|
||||||
if (bind == null || bind.save == null || bind.save.GetInstanceId() != map.GetInstanceId())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var players = map.GetPlayers();
|
|
||||||
if (!players.Empty())
|
|
||||||
foreach (var otherPlayer in players)
|
|
||||||
{
|
|
||||||
if (otherPlayer.IsGameMaster())
|
|
||||||
continue;
|
|
||||||
if (!otherPlayer.m_InstanceValid) // ignore players that currently have a homebind timer active
|
|
||||||
continue;
|
|
||||||
if (group != otherPlayer.GetGroup())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// instance is invalid if we are not grouped and there are other players
|
// instance is invalid if we are not grouped and there are other players
|
||||||
if (map.GetPlayersCountExceptGMs() > 1)
|
if (map.GetPlayersCountExceptGMs() > 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// check if the player is bound to this instance
|
|
||||||
InstanceBind bind = GetBoundInstance(map.GetId(), map.GetDifficultyID());
|
|
||||||
if (bind == null || bind.save == null || bind.save.GetInstanceId() != map.GetInstanceId())
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -166,7 +166,9 @@ namespace Game.Groups
|
|||||||
|
|
||||||
DB.Characters.Execute(stmt);
|
DB.Characters.Execute(stmt);
|
||||||
|
|
||||||
ConvertLeaderInstancesToGroup(leader, this, false);
|
InstanceMap leaderInstance = leader.GetMap().ToInstanceMap();
|
||||||
|
if (leaderInstance != null)
|
||||||
|
leaderInstance.TrySetOwningGroup(this);
|
||||||
|
|
||||||
Cypher.Assert(AddMember(leader)); // If the leader can't be added to a new group because it appears full, something is clearly wrong.
|
Cypher.Assert(AddMember(leader)); // If the leader can't be added to a new group because it appears full, something is clearly wrong.
|
||||||
}
|
}
|
||||||
@@ -691,9 +693,6 @@ namespace Game.Groups
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the permanent binds from the new leader to the group
|
|
||||||
ConvertLeaderInstancesToGroup(newLeader, this, true);
|
|
||||||
|
|
||||||
// Update the group leader
|
// Update the group leader
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_GROUP_LEADER);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_GROUP_LEADER);
|
||||||
|
|
||||||
@@ -721,47 +720,6 @@ namespace Game.Groups
|
|||||||
BroadcastPacket(groupNewLeader, true);
|
BroadcastPacket(groupNewLeader, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ConvertLeaderInstancesToGroup(Player player, Group group, bool switchLeader)
|
|
||||||
{
|
|
||||||
// copy all binds to the group, when changing leader it's assumed the character
|
|
||||||
// will not have any solo binds
|
|
||||||
foreach (var difficultyDic in player.m_boundInstances.Values)
|
|
||||||
{
|
|
||||||
foreach (var pair in difficultyDic)
|
|
||||||
{
|
|
||||||
if (!switchLeader || group.GetBoundInstance(pair.Value.save.GetDifficultyID(), pair.Key) == null)
|
|
||||||
if (pair.Value.extendState != 0) // not expired
|
|
||||||
group.BindToInstance(pair.Value.save, pair.Value.perm, false);
|
|
||||||
|
|
||||||
// permanent binds are not removed
|
|
||||||
if (switchLeader && !pair.Value.perm)
|
|
||||||
{
|
|
||||||
player.UnbindInstance(pair, difficultyDic, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if group leader is in a non-raid dungeon map and nobody is actually bound to this map then the group can "take over" the instance
|
|
||||||
// (example: two-player group disbanded by disconnect where the player reconnects within 60 seconds and the group is reformed)
|
|
||||||
Map playerMap = player.GetMap();
|
|
||||||
if (playerMap)
|
|
||||||
{
|
|
||||||
if (!switchLeader && playerMap.IsNonRaidDungeon())
|
|
||||||
{
|
|
||||||
InstanceSave save = Global.InstanceSaveMgr.GetInstanceSave(playerMap.GetInstanceId());
|
|
||||||
if (save != null)
|
|
||||||
{
|
|
||||||
if (save.GetGroupCount() == 0 && save.GetPlayerCount() == 0)
|
|
||||||
{
|
|
||||||
Log.outDebug(LogFilter.Maps, "Group.ConvertLeaderInstancesToGroup: Group for player {0} is taking over unbound instance map {1} with Id {2}", player.GetName(), playerMap.GetId(), playerMap.GetInstanceId());
|
|
||||||
// if nobody is saved to this, then the save wasn't permanent
|
|
||||||
group.BindToInstance(save, false, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Disband(bool hideDestroy = false)
|
public void Disband(bool hideDestroy = false)
|
||||||
{
|
{
|
||||||
Global.ScriptMgr.OnGroupDisband(this);
|
Global.ScriptMgr.OnGroupDisband(this);
|
||||||
@@ -1585,45 +1543,9 @@ namespace Game.Groups
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InstanceBind BindToInstance(InstanceSave save, bool permanent, bool load = false)
|
public void LinkOwnedInstance(GroupInstanceReference refe)
|
||||||
{
|
{
|
||||||
if (save == null || IsBGGroup() || IsBFGroup())
|
m_ownedInstancesMgr.InsertLast(refe);
|
||||||
return null;
|
|
||||||
|
|
||||||
if (!m_boundInstances.ContainsKey(save.GetDifficultyID()))
|
|
||||||
m_boundInstances[save.GetDifficultyID()] = new Dictionary<uint, InstanceBind>();
|
|
||||||
|
|
||||||
if (!m_boundInstances[save.GetDifficultyID()].ContainsKey(save.GetMapId()))
|
|
||||||
m_boundInstances[save.GetDifficultyID()][save.GetMapId()] = new InstanceBind();
|
|
||||||
|
|
||||||
InstanceBind bind = m_boundInstances[save.GetDifficultyID()][save.GetMapId()];
|
|
||||||
if (!load && (bind.save == null || permanent != bind.perm || save != bind.save))
|
|
||||||
{
|
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.REP_GROUP_INSTANCE);
|
|
||||||
|
|
||||||
stmt.AddValue(0, m_dbStoreId);
|
|
||||||
stmt.AddValue(1, save.GetInstanceId());
|
|
||||||
stmt.AddValue(2, permanent);
|
|
||||||
|
|
||||||
DB.Characters.Execute(stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bind.save != save)
|
|
||||||
{
|
|
||||||
if (bind.save != null)
|
|
||||||
bind.save.RemoveGroup(this);
|
|
||||||
save.AddGroup(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bind.save = save;
|
|
||||||
bind.perm = permanent;
|
|
||||||
if (!load)
|
|
||||||
Log.outDebug(LogFilter.Maps, "Group.BindToInstance: Group ({0}, storage id: {1}) is now bound to map {2}, instance {3}, difficulty {4}",
|
|
||||||
GetGUID().ToString(), m_dbStoreId, save.GetMapId(), save.GetInstanceId(), save.GetDifficultyID());
|
|
||||||
|
|
||||||
m_boundInstances[save.GetDifficultyID()][save.GetMapId()] = bind;
|
|
||||||
|
|
||||||
return bind;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnbindInstance(uint mapid, Difficulty difficulty, bool unload = false)
|
public void UnbindInstance(uint mapid, Difficulty difficulty, bool unload = false)
|
||||||
@@ -2199,6 +2121,7 @@ namespace Game.Groups
|
|||||||
ObjectGuid m_masterLooterGuid;
|
ObjectGuid m_masterLooterGuid;
|
||||||
Dictionary<Difficulty, Dictionary<uint, InstanceBind>> m_boundInstances = new();
|
Dictionary<Difficulty, Dictionary<uint, InstanceBind>> m_boundInstances = new();
|
||||||
Dictionary<uint, Tuple<ObjectGuid, uint>> m_recentInstances = new();
|
Dictionary<uint, Tuple<ObjectGuid, uint>> m_recentInstances = new();
|
||||||
|
GroupInstanceRefManager m_ownedInstancesMgr = new();
|
||||||
byte[] m_subGroupsCounts;
|
byte[] m_subGroupsCounts;
|
||||||
ObjectGuid m_guid;
|
ObjectGuid m_guid;
|
||||||
uint m_dbStoreId;
|
uint m_dbStoreId;
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2020 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.Dynamic;
|
||||||
|
using Game.Maps;
|
||||||
|
|
||||||
|
namespace Game.Groups
|
||||||
|
{
|
||||||
|
public class GroupInstanceReference : Reference<Group, InstanceMap>
|
||||||
|
{
|
||||||
|
~GroupInstanceReference() { Unlink(); }
|
||||||
|
|
||||||
|
public new GroupInstanceReference Next() { return (GroupInstanceReference)base.Next(); }
|
||||||
|
|
||||||
|
public override void TargetObjectBuildLink()
|
||||||
|
{
|
||||||
|
GetTarget().LinkOwnedInstance(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GroupInstanceRefManager : RefManager<Group, InstanceMap>
|
||||||
|
{
|
||||||
|
public new GroupInstanceReference GetFirst() { return (GroupInstanceReference)base.GetFirst(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-1
@@ -4914,7 +4914,7 @@ namespace Game.Maps
|
|||||||
if (i_instanceLock != null)
|
if (i_instanceLock != null)
|
||||||
{
|
{
|
||||||
MapDb2Entries entries = new(GetEntry(), GetMapDifficulty());
|
MapDb2Entries entries = new(GetEntry(), GetMapDifficulty());
|
||||||
if (entries.IsInstanceIdBound() || IsRaid() || entries.MapDifficulty.IsRestoringDungeonState() || !i_owningGroupRef.isValid())
|
if (entries.IsInstanceIdBound() || IsRaid() || entries.MapDifficulty.IsRestoringDungeonState() || !i_owningGroupRef.IsValid())
|
||||||
{
|
{
|
||||||
InstanceLockData lockData = i_instanceLock.GetInstanceInitializationData();
|
InstanceLockData lockData = i_instanceLock.GetInstanceInitializationData();
|
||||||
i_data.SetCompletedEncountersMask(lockData.CompletedEncountersMask);
|
i_data.SetCompletedEncountersMask(lockData.CompletedEncountersMask);
|
||||||
@@ -4931,6 +4931,14 @@ namespace Game.Maps
|
|||||||
i_data.Create();
|
i_data.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Group GetOwningGroup() { return i_owningGroupRef.GetTarget(); }
|
||||||
|
|
||||||
|
public void TrySetOwningGroup(Group group)
|
||||||
|
{
|
||||||
|
if (!i_owningGroupRef.IsValid())
|
||||||
|
i_owningGroupRef.Link(group, this);
|
||||||
|
}
|
||||||
|
|
||||||
public bool Reset(InstanceResetMethod method)
|
public bool Reset(InstanceResetMethod method)
|
||||||
{
|
{
|
||||||
// note: since the map may not be loaded when the instance needs to be reset
|
// note: since the map may not be loaded when the instance needs to be reset
|
||||||
@@ -5149,6 +5157,7 @@ namespace Game.Maps
|
|||||||
uint i_script_id;
|
uint i_script_id;
|
||||||
InstanceScenario i_scenario;
|
InstanceScenario i_scenario;
|
||||||
InstanceLock i_instanceLock;
|
InstanceLock i_instanceLock;
|
||||||
|
GroupInstanceReference i_owningGroupRef = new();
|
||||||
bool m_resetAfterUnload;
|
bool m_resetAfterUnload;
|
||||||
bool m_unloadWhenEmpty;
|
bool m_unloadWhenEmpty;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ namespace Game.Entities
|
|||||||
|
|
||||||
map.LoadRespawnTimes();
|
map.LoadRespawnTimes();
|
||||||
map.LoadCorpseData();
|
map.LoadCorpseData();
|
||||||
|
if (group != null)
|
||||||
|
map.TrySetOwningGroup(group);
|
||||||
|
|
||||||
map.CreateInstanceData();
|
map.CreateInstanceData();
|
||||||
map.SetInstanceScenario(Global.ScenarioMgr.CreateInstanceScenario(map, team));
|
map.SetInstanceScenario(Global.ScenarioMgr.CreateInstanceScenario(map, team));
|
||||||
|
|||||||
Reference in New Issue
Block a user