aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Entities/Player/Player.cpp32
-rw-r--r--src/server/game/Groups/Group.cpp75
-rw-r--r--src/server/game/Groups/Group.h5
-rw-r--r--src/server/game/Groups/GroupInstanceRefManager.h43
-rw-r--r--src/server/game/Groups/GroupInstanceReference.cpp32
-rw-r--r--src/server/game/Groups/GroupInstanceReference.h40
-rw-r--r--src/server/game/Maps/Map.cpp6
-rw-r--r--src/server/game/Maps/Map.h4
-rw-r--r--src/server/game/Maps/MapManager.cpp2
9 files changed, 141 insertions, 98 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 5b4d2f42231..6018cdeee61 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -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;
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 127b0dab275..f8929654908 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -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)
diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h
index e3236b7eb6d..7860a81fd5c 100644
--- a/src/server/game/Groups/Group.h
+++ b/src/server/game/Groups/Group.h
@@ -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)
diff --git a/src/server/game/Groups/GroupInstanceRefManager.h b/src/server/game/Groups/GroupInstanceRefManager.h
new file mode 100644
index 00000000000..af6015f2355
--- /dev/null
+++ b/src/server/game/Groups/GroupInstanceRefManager.h
@@ -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__
diff --git a/src/server/game/Groups/GroupInstanceReference.cpp b/src/server/game/Groups/GroupInstanceReference.cpp
new file mode 100644
index 00000000000..2628bb8074c
--- /dev/null
+++ b/src/server/game/Groups/GroupInstanceReference.cpp
@@ -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()
+{
+}
diff --git a/src/server/game/Groups/GroupInstanceReference.h b/src/server/game/Groups/GroupInstanceReference.h
new file mode 100644
index 00000000000..effe449d453
--- /dev/null
+++ b/src/server/game/Groups/GroupInstanceReference.h
@@ -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__
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index a30e752f555..4c838cd7d09 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -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
*/
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index e3d622f49b0..e1e70b4ab6f 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -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
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index a89324eb1a1..8a525d2b64e 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -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));