Game/Maps: Instance handling follow-up:
- Fix a bug where a player could maintain a conflicting non-perm solo bind if they were in the instance when invited to group. Closes #16150.
- If a group is created while the leader is in an instance that nobody is bound to, the group will take over the instance and bind to it. This stops the homebind timer when reforming group after disconnects and the like.
(cherry picked from commit 0f0a51b87a)
This commit is contained in:
1 parent
94a5629949
commit
27f0edde0f
6 files changed
+45
-33
No files matched your search
@@ -19132,31 +19132,6 @@ void Player::SendSavedInstances()
|
||||
}
|
||||
}
|
||||
|
||||
/// convert the player's binds to the group
|
||||
void Player::ConvertInstancesToGroup(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
|
||||
|
||||
for (uint8 i = 0; i < MAX_DIFFICULTY; ++i)
|
||||
{
|
||||
for (BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();)
|
||||
{
|
||||
if (!switchLeader || !group->GetBoundInstance(itr->second.save->GetDifficulty(), itr->first))
|
||||
group->BindToInstance(itr->second.save, itr->second.perm, false);
|
||||
|
||||
// permanent binds are not removed
|
||||
if (switchLeader && !itr->second.perm)
|
||||
{
|
||||
// increments itr in call
|
||||
player->UnbindInstance(itr, Difficulty(i), false);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::Satisfy(AccessRequirement const* ar, uint32 target_map, bool report)
|
||||
{
|
||||
if (!IsGameMaster() && ar)
|
||||
|
||||
@@ -2406,7 +2406,6 @@ class Player : public Unit, public GridObject<Player>
|
||||
bool HasPendingBind() const { return _pendingBindId > 0; }
|
||||
void SendRaidInfo();
|
||||
void SendSavedInstances();
|
||||
static void ConvertInstancesToGroup(Player* player, Group* group, bool switchLeader);
|
||||
bool Satisfy(AccessRequirement const* ar, uint32 target_map, bool report = false);
|
||||
bool CheckInstanceValidity(bool /*isLogin*/);
|
||||
bool CheckInstanceCount(uint32 instanceId) const;
|
||||
|
||||
@@ -148,10 +148,9 @@ bool Group::Create(Player* leader)
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
Group::ConvertLeaderInstancesToGroup(leader, this, false);
|
||||
|
||||
ASSERT(AddMember(leader)); // If the leader can't be added to a new group because it appears full, something is clearly wrong.
|
||||
|
||||
Player::ConvertInstancesToGroup(leader, this, false);
|
||||
}
|
||||
else if (!AddMember(leader))
|
||||
return false;
|
||||
@@ -406,9 +405,7 @@ bool Group::AddMember(Player* player)
|
||||
player->SetGroup(this, subGroup);
|
||||
|
||||
// if the same group invites the player back, cancel the homebind timer
|
||||
InstanceGroupBind* bind = GetBoundInstance(player);
|
||||
if (bind && bind->save->GetInstanceId() == player->GetInstanceId())
|
||||
player->m_InstanceValid = true;
|
||||
player->m_InstanceValid = player->CheckInstanceValidity(false);
|
||||
|
||||
if (!isRaidGroup()) // reset targetIcons for non-raid-groups
|
||||
{
|
||||
@@ -685,7 +682,7 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid)
|
||||
}
|
||||
|
||||
// Copy the permanent binds from the new leader to the group
|
||||
Player::ConvertInstancesToGroup(newLeader, this, true);
|
||||
Group::ConvertLeaderInstancesToGroup(newLeader, this, true);
|
||||
|
||||
// Update the group leader
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_LEADER);
|
||||
@@ -711,6 +708,42 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid)
|
||||
BroadcastPacket(&data, true);
|
||||
}
|
||||
|
||||
/// convert the player's binds to the group
|
||||
void Group::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
|
||||
for (uint8 i = 0; i < MAX_DIFFICULTY; ++i)
|
||||
{
|
||||
for (Player::BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();)
|
||||
{
|
||||
if (!switchLeader || !group->GetBoundInstance(itr->second.save->GetDifficulty(), itr->first))
|
||||
group->BindToInstance(itr->second.save, itr->second.perm, false);
|
||||
|
||||
// permanent binds are not removed
|
||||
if (switchLeader && !itr->second.perm)
|
||||
{
|
||||
// increments itr in call
|
||||
player->UnbindInstance(itr, Difficulty(i), false);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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) */
|
||||
if (Map* playerMap = player->GetMap())
|
||||
if (!switchLeader && playerMap->IsNonRaidDungeon())
|
||||
if (InstanceSave* save = sInstanceSaveMgr->GetInstanceSave(playerMap->GetInstanceId()))
|
||||
if (save->GetGroupCount() == 0 && save->GetPlayerCount() == 0)
|
||||
{
|
||||
TC_LOG_DEBUG("maps", "Group::ConvertLeaderInstancesToGroup: Group for player %s is taking over unbound instance map %d with Id %d", player->GetName().c_str(), playerMap->GetId(), playerMap->GetInstanceId());
|
||||
// if nobody is saved to this, then the save wasn't permanent
|
||||
group->BindToInstance(save, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Group::Disband(bool hideDestroy /* = false */)
|
||||
{
|
||||
sScriptMgr->OnGroupDisband(this);
|
||||
|
||||
@@ -198,6 +198,7 @@ class Group
|
||||
bool AddMember(Player* player);
|
||||
bool RemoveMember(ObjectGuid guid, const RemoveMethod &method = GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker = ObjectGuid::Empty, const char* reason = NULL);
|
||||
void ChangeLeader(ObjectGuid guid);
|
||||
static void ConvertLeaderInstancesToGroup(Player* player, Group* group, bool switchLeader);
|
||||
void SetLootMethod(LootMethod method);
|
||||
void SetLooterGuid(ObjectGuid guid);
|
||||
void SetMasterLooterGuid(ObjectGuid guid);
|
||||
|
||||
@@ -3031,7 +3031,7 @@ bool InstanceMap::AddPlayerToMap(Player* player)
|
||||
{
|
||||
if (group)
|
||||
{
|
||||
// solo saves should be reset when entering a group
|
||||
// solo saves should have been reset when the map was loaded
|
||||
InstanceGroupBind* groupBind = group->GetBoundInstance(this);
|
||||
if (playerBind && playerBind->save != mapSave)
|
||||
{
|
||||
|
||||
@@ -163,7 +163,11 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player, u
|
||||
{
|
||||
groupBind = group->GetBoundInstance(this);
|
||||
if (groupBind)
|
||||
{
|
||||
// solo saves should be reset when entering a group's instance
|
||||
player->UnbindInstance(GetId(), player->GetDifficulty(IsRaid()));
|
||||
pSave = groupBind->save;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pSave)
|
||||
|
||||
Reference in new issue
Block a user