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:
treeston authored and ariel- committed 2016-01-11 01:51:25 -03:00
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)
-1
View File
@@ -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;
+39 -6
View File
@@ -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);
+1
View File
@@ -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);
+1 -1
View File
@@ -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)
{
+4
View File
@@ -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)