Core/Maps: Check group that owns instance (first group to enter a given instance id owns it)

This commit is contained in:
Shauren
2019-12-26 13:30:32 +01:00
parent 17665c929c
commit a131542855
9 changed files with 141 additions and 98 deletions

View File

@@ -19353,46 +19353,26 @@ bool Player::CheckInstanceValidity(bool /*isLogin*/)
// non-instances are always valid
Map* map = FindMap();
if (!map || !map->IsDungeon())
InstanceMap* instance = map ? map->ToInstanceMap() : nullptr;
if (!instance)
return true;
Group* group = GetGroup();
// raid instances require the player to be in a raid group to be valid
if (map->IsRaid() && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID) && (map->GetEntry()->Expansion() >= sWorld->getIntConfig(CONFIG_EXPANSION)))
if (!GetGroup() || !GetGroup()->isRaidGroup())
if (!group || !group->isRaidGroup())
return false;
if (Group* group = GetGroup())
if (group)
{
// check if player's group is bound to this instance
InstanceGroupBind* bind = group->GetBoundInstance(map->GetDifficultyID(), map->GetId());
if (!bind || !bind->save || bind->save->GetInstanceId() != map->GetInstanceId())
if (group != instance->GetOwningGroup())
return false;
Map::PlayerList const& players = map->GetPlayers();
if (!players.isEmpty())
for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
{
if (Player* otherPlayer = it->GetSource())
{
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
InstancePlayerBind* bind = GetBoundInstance(map->GetId(), map->GetDifficultyID());
if (!bind || !bind->save || bind->save->GetInstanceId() != map->GetInstanceId())
return false;
}
return true;

View File

@@ -193,7 +193,8 @@ bool Group::Create(Player* leader)
CharacterDatabase.Execute(stmt);
Group::ConvertLeaderInstancesToGroup(leader, this, false);
if (InstanceMap* leaderInstance = leader->GetMap()->ToInstanceMap())
leaderInstance->TrySetOwningGroup(this);
bool addMemberResult = AddMember(leader);
ASSERT(addMemberResult); // If the leader can't be added to a new group because it appears full, something is clearly wrong.
@@ -715,9 +716,6 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid, int8 partyIndex)
}
}
// Copy the permanent binds from the new leader to the group
Group::ConvertLeaderInstancesToGroup(newLeader, this, true);
// Update the group leader
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_LEADER);
@@ -744,43 +742,6 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid, int8 partyIndex)
BroadcastPacket(groupNewLeader.Write(), 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 (auto difficultyItr = player->m_boundInstances.begin(); difficultyItr != player->m_boundInstances.end(); ++difficultyItr)
{
for (auto itr = difficultyItr->second.begin(); itr != difficultyItr->second.end();)
{
if (!switchLeader || !group->GetBoundInstance(itr->second.save->GetDifficultyID(), itr->first))
if (itr->second.extendState) // not expired
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, difficultyItr, 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->FindMap())
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);
@@ -1596,37 +1557,9 @@ InstanceGroupBind* Group::GetBoundInstance(Difficulty difficulty, uint32 mapId)
return nullptr;
}
InstanceGroupBind* Group::BindToInstance(InstanceSave* save, bool permanent, bool load)
void Group::LinkOwnedInstance(GroupInstanceReference* ref)
{
if (!save || isBGGroup() || isBFGroup())
return nullptr;
InstanceGroupBind& bind = m_boundInstances[save->GetDifficultyID()][save->GetMapId()];
if (!load && (!bind.save || permanent != bind.perm || save != bind.save))
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_GROUP_INSTANCE);
stmt->setUInt32(0, m_dbStoreId);
stmt->setUInt32(1, save->GetInstanceId());
stmt->setBool(2, permanent);
CharacterDatabase.Execute(stmt);
}
if (bind.save != save)
{
if (bind.save)
bind.save->RemoveGroup(this);
save->AddGroup(this);
}
bind.save = save;
bind.perm = permanent;
if (!load)
TC_LOG_DEBUG("maps", "Group::BindToInstance: %s, storage id: %u is now bound to map %d, instance %d, difficulty %d",
GetGUID().ToString().c_str(), m_dbStoreId, save->GetMapId(), save->GetInstanceId(), static_cast<uint32>(save->GetDifficultyID()));
return &bind;
m_ownedInstancesMgr.insertLast(ref);
}
void Group::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload)

View File

@@ -20,6 +20,7 @@
#include "DBCEnums.h"
#include "DatabaseEnvFwd.h"
#include "GroupInstanceRefManager.h"
#include "GroupRefManager.h"
#include "Object.h"
#include "RaceMask.h"
@@ -216,7 +217,6 @@ class TC_GAME_API Group
bool AddMember(Player* player);
bool RemoveMember(ObjectGuid guid, RemoveMethod method = GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker = ObjectGuid::Empty, const char* reason = nullptr);
void ChangeLeader(ObjectGuid guid, int8 partyIndex = 0);
static void ConvertLeaderInstancesToGroup(Player* player, Group* group, bool switchLeader);
void SetLootMethod(LootMethod method);
void SetLooterGuid(ObjectGuid guid);
void SetMasterLooterGuid(ObjectGuid guid);
@@ -364,6 +364,8 @@ class TC_GAME_API Group
m_recentInstances[mapId] = { instanceOwner, instanceId };
}
void LinkOwnedInstance(GroupInstanceReference* ref);
void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false);
InstanceGroupBind* GetBoundInstance(Player* player);
InstanceGroupBind* GetBoundInstance(Map* aMap);
@@ -410,6 +412,7 @@ class TC_GAME_API Group
ObjectGuid m_masterLooterGuid;
BoundInstancesMap m_boundInstances;
std::unordered_map<uint32 /*mapId*/, std::pair<ObjectGuid /*instanceOwner*/, uint32 /*instanceId*/>> m_recentInstances;
GroupInstanceRefManager m_ownedInstancesMgr;
uint8* m_subGroupsCounts;
ObjectGuid m_guid;
uint32 m_dbStoreId; // Represents the ID used in database (Can be reused by other groups if group was disbanded)

View File

@@ -0,0 +1,43 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* 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 2 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/>.
*/
#ifndef GroupInstanceRefManager_h__
#define GroupInstanceRefManager_h__
#include "GroupInstanceReference.h"
#include "RefManager.h"
class Group;
class InstanceMap;
class GroupInstanceRefManager : public RefManager<Group, InstanceMap>
{
public:
typedef LinkedListHead::Iterator<GroupInstanceReference> iterator;
typedef LinkedListHead::Iterator<GroupInstanceReference const> const_iterator;
GroupInstanceReference* getFirst() { return ((GroupInstanceReference*)RefManager<Group, InstanceMap>::getFirst()); }
GroupInstanceReference const* getFirst() const { return ((GroupInstanceReference const*)RefManager<Group, InstanceMap>::getFirst()); }
iterator begin() { return iterator(getFirst()); }
iterator end() { return iterator(nullptr); }
const_iterator begin() const { return const_iterator(getFirst()); }
const_iterator end() const { return const_iterator(nullptr); }
};
#endif // GroupInstanceRefManager_h__

View File

@@ -0,0 +1,32 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* 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 2 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/>.
*/
#include "Group.h"
#include "GroupInstanceReference.h"
void GroupInstanceReference::targetObjectBuildLink()
{
getTarget()->LinkOwnedInstance(this);
}
void GroupInstanceReference::targetObjectDestroyLink()
{
}
void GroupInstanceReference::sourceObjectDestroyLink()
{
}

View File

@@ -0,0 +1,40 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* 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 2 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/>.
*/
#ifndef GroupInstanceReference_h__
#define GroupInstanceReference_h__
#include "LinkedReference/Reference.h"
class Group;
class InstanceMap;
class TC_GAME_API GroupInstanceReference : public Reference<Group, InstanceMap>
{
public:
GroupInstanceReference() : Reference<Group, InstanceMap>() { }
~GroupInstanceReference() { unlink(); }
GroupInstanceReference* next() { return (GroupInstanceReference*)Reference<Group, InstanceMap>::next(); }
GroupInstanceReference const* next() const { return (GroupInstanceReference const*)Reference<Group, InstanceMap>::next(); }
protected:
void targetObjectBuildLink() override;
void targetObjectDestroyLink() override;
void sourceObjectDestroyLink() override;
};
#endif // GroupInstanceReference_h__

View File

@@ -2958,6 +2958,12 @@ void InstanceMap::CreateInstanceData()
i_data->Create();
}
void InstanceMap::TrySetOwningGroup(Group* group)
{
if (!i_owningGroupRef.isValid())
i_owningGroupRef.link(group, this);
}
/*
Returns true if there are no players in the instance
*/

View File

@@ -25,6 +25,7 @@
#include "DynamicTree.h"
#include "GridDefines.h"
#include "GridRefManager.h"
#include "GroupInstanceReference.h"
#include "MapDefines.h"
#include "MapReference.h"
#include "MapRefManager.h"
@@ -831,6 +832,8 @@ class TC_GAME_API InstanceMap : public Map
Team GetTeamInInstance() const { return GetTeamIdInInstance() == TEAM_ALLIANCE ? ALLIANCE : HORDE; }
virtual void InitVisibilityDistance() override;
Group* GetOwningGroup() const { return i_owningGroupRef.getTarget(); }
void TrySetOwningGroup(Group* group);
std::string GetDebugInfo() const override;
private:
@@ -840,6 +843,7 @@ class TC_GAME_API InstanceMap : public Map
uint32 i_script_id;
InstanceScenario* i_scenario;
InstanceLock* i_instanceLock;
GroupInstanceReference i_owningGroupRef;
};
class TC_GAME_API BattlegroundMap : public Map

View File

@@ -103,6 +103,8 @@ InstanceMap* MapManager::CreateInstance(uint32 mapId, uint32 instanceId, Instanc
map->LoadRespawnTimes();
map->LoadCorpseData();
if (group)
map->TrySetOwningGroup(group);
map->CreateInstanceData();
map->SetInstanceScenario(sScenarioMgr->CreateInstanceScenario(map, team));