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:
hondacrx
2022-10-04 10:12:41 -04:00
parent d3dde761a2
commit 793cf91a24
5 changed files with 62 additions and 106 deletions
+5 -22
View File
@@ -584,44 +584,27 @@ namespace Game.Entities
// non-instances are always valid
Map map = GetMap();
if (!map || !map.IsDungeon())
InstanceMap instance = map?.ToInstanceMap();
if (instance == null)
return true;
Group group = GetGroup();
// 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 (!GetGroup() || !GetGroup().IsRaidGroup())
if (group == null || group.IsRaidGroup())
return false;
Group group = GetGroup();
if (group)
{
// check if player's group is bound to this instance
InstanceBind bind = group.GetBoundInstance(map.GetDifficultyID(), map.GetId());
if (bind == null || bind.save == null || bind.save.GetInstanceId() != map.GetInstanceId())
if (group != instance.GetOwningGroup())
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
{
// instance is invalid if we are not grouped and there are other players
if (map.GetPlayersCountExceptGMs() > 1)
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;
+6 -83
View File
@@ -166,7 +166,9 @@ namespace Game.Groups
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.
}
@@ -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
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_GROUP_LEADER);
@@ -721,47 +720,6 @@ namespace Game.Groups
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)
{
Global.ScriptMgr.OnGroupDisband(this);
@@ -1585,45 +1543,9 @@ namespace Game.Groups
return null;
}
public InstanceBind BindToInstance(InstanceSave save, bool permanent, bool load = false)
public void LinkOwnedInstance(GroupInstanceReference refe)
{
if (save == null || IsBGGroup() || IsBFGroup())
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;
m_ownedInstancesMgr.InsertLast(refe);
}
public void UnbindInstance(uint mapid, Difficulty difficulty, bool unload = false)
@@ -2199,6 +2121,7 @@ namespace Game.Groups
ObjectGuid m_masterLooterGuid;
Dictionary<Difficulty, Dictionary<uint, InstanceBind>> m_boundInstances = new();
Dictionary<uint, Tuple<ObjectGuid, uint>> m_recentInstances = new();
GroupInstanceRefManager m_ownedInstancesMgr = new();
byte[] m_subGroupsCounts;
ObjectGuid m_guid;
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
View File
@@ -4914,7 +4914,7 @@ namespace Game.Maps
if (i_instanceLock != null)
{
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();
i_data.SetCompletedEncountersMask(lockData.CompletedEncountersMask);
@@ -4931,6 +4931,14 @@ namespace Game.Maps
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)
{
// 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;
InstanceScenario i_scenario;
InstanceLock i_instanceLock;
GroupInstanceReference i_owningGroupRef = new();
bool m_resetAfterUnload;
bool m_unloadWhenEmpty;
}
+2
View File
@@ -91,6 +91,8 @@ namespace Game.Entities
map.LoadRespawnTimes();
map.LoadCorpseData();
if (group != null)
map.TrySetOwningGroup(group);
map.CreateInstanceData();
map.SetInstanceScenario(Global.ScenarioMgr.CreateInstanceScenario(map, team));