mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Core/Maps: Check group that owns instance (first group to enter a given instance id owns it)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
43
src/server/game/Groups/GroupInstanceRefManager.h
Normal file
43
src/server/game/Groups/GroupInstanceRefManager.h
Normal 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__
|
||||
32
src/server/game/Groups/GroupInstanceReference.cpp
Normal file
32
src/server/game/Groups/GroupInstanceReference.cpp
Normal 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()
|
||||
{
|
||||
}
|
||||
40
src/server/game/Groups/GroupInstanceReference.h
Normal file
40
src/server/game/Groups/GroupInstanceReference.h
Normal 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__
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user