aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWyrserth <43747507+Wyrserth@users.noreply.github.com>2019-06-15 14:19:58 +0200
committerGiacomo Pozzoni <giacomopoz@gmail.com>2019-06-15 14:19:58 +0200
commite906a2fe7d71fc17de9f7ea4778970beb3f9265e (patch)
tree02ac22a52d44549ee829eece372fd888e1d4fa44
parente6ad9b10cf381625ca1955cf6081ea1a8b14de11 (diff)
Core/Group: implement automatic party/raid leader change when the leader has been offline for two minutes (#23398)
* Core/Group: implement automatic party/raid leader change when the leader has been offline for two minutes. * Add #23396 to make testing easier. * Prioritize assistants in raids. * Fix dumb mistake and apply suggested change, thanks VincentVanclef and jackpoz!
-rw-r--r--src/server/game/Groups/Group.cpp62
-rw-r--r--src/server/game/Groups/Group.h9
-rw-r--r--src/server/game/Groups/GroupMgr.cpp6
-rw-r--r--src/server/game/Groups/GroupMgr.h2
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp2
-rw-r--r--src/server/game/Server/WorldSession.cpp13
-rw-r--r--src/server/game/World/World.cpp3
7 files changed, 88 insertions, 9 deletions
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 3a63033575d..74fc5cbdfb7 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -63,7 +63,7 @@ Loot* Roll::getLoot()
Group::Group() : m_leaderGuid(), m_leaderName(""), m_groupType(GROUPTYPE_NORMAL),
m_dungeonDifficulty(DUNGEON_DIFFICULTY_NORMAL), m_raidDifficulty(RAID_DIFFICULTY_10MAN_NORMAL),
m_bgGroup(nullptr), m_bfGroup(nullptr), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(),
-m_masterLooterGuid(), m_subGroupsCounts(nullptr), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0)
+m_masterLooterGuid(), m_subGroupsCounts(nullptr), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0), m_isLeaderOffline(false)
{
for (uint8 i = 0; i < TARGETICONCOUNT; ++i)
m_targetIcons[i].Clear();
@@ -99,6 +99,55 @@ Group::~Group()
delete[] m_subGroupsCounts;
}
+void Group::Update(uint32 diff)
+{
+ if (m_isLeaderOffline && (m_groupType == GROUPTYPE_NORMAL || m_groupType == GROUPTYPE_RAID))
+ {
+ m_leaderOfflineTimer.Update(diff);
+ if (m_leaderOfflineTimer.Passed())
+ {
+ SelectNewPartyOrRaidLeader();
+ m_isLeaderOffline = false;
+ }
+ }
+}
+
+void Group::SelectNewPartyOrRaidLeader()
+{
+ Player* newLeader = nullptr;
+
+ // Attempt to give leadership to main assistant first
+ if (m_groupType == GROUPTYPE_RAID)
+ {
+ for (auto memberSlot : m_memberSlots)
+ {
+ if ((memberSlot.flags & MEMBER_FLAG_ASSISTANT) == MEMBER_FLAG_ASSISTANT)
+ if (Player* player = ObjectAccessor::FindPlayer(memberSlot.guid))
+ {
+ newLeader = player;
+ break;
+ }
+ }
+ }
+
+ // If there aren't assistants in raid, or if the group is not a raid, pick the first available member
+ if (!newLeader)
+ {
+ for (auto memberSlot : m_memberSlots)
+ if (Player* player = ObjectAccessor::FindPlayer(memberSlot.guid))
+ {
+ newLeader = player;
+ break;
+ }
+ }
+
+ if (newLeader)
+ {
+ ChangeLeader(newLeader->GetGUID());
+ SendUpdate();
+ }
+}
+
bool Group::Create(Player* leader)
{
ObjectGuid leaderGuid = leader->GetGUID();
@@ -2554,3 +2603,14 @@ void Group::ToggleGroupMemberFlag(member_witerator slot, uint8 flag, bool apply)
else
slot->flags &= ~flag;
}
+
+void Group::StartLeaderOfflineTimer()
+{
+ m_isLeaderOffline = true;
+ m_leaderOfflineTimer.Reset(2 * MINUTE * IN_MILLISECONDS);
+}
+
+void Group::StopLeaderOfflineTimer()
+{
+ m_isLeaderOffline = false;
+}
diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h
index 842c39cbcda..a7a962f5758 100644
--- a/src/server/game/Groups/Group.h
+++ b/src/server/game/Groups/Group.h
@@ -24,6 +24,7 @@
#include "GroupRefManager.h"
#include "Loot.h"
#include "SharedDefines.h"
+#include "Timer.h"
#include <map>
class Battlefield;
@@ -184,6 +185,8 @@ class TC_GAME_API Group
Group();
~Group();
+ void Update(uint32 diff);
+
// group manipulation methods
bool Create(Player* leader);
void LoadGroupFromDB(Field* field);
@@ -327,6 +330,10 @@ class TC_GAME_API Group
InstanceGroupBind* GetBoundInstance(Difficulty difficulty, uint32 mapId);
BoundInstancesMap& GetBoundInstances(Difficulty difficulty);
+ void StartLeaderOfflineTimer();
+ void StopLeaderOfflineTimer();
+ void SelectNewPartyOrRaidLeader();
+
// FG: evil hacks
void BroadcastGroupUpdate(void);
@@ -363,5 +370,7 @@ class TC_GAME_API Group
uint32 m_counter; // used only in SMSG_GROUP_LIST
uint32 m_maxEnchantingLevel;
uint32 m_dbStoreId; // Represents the ID used in database (Can be reused by other groups if group was disbanded)
+ bool m_isLeaderOffline;
+ TimeTrackerSmall m_leaderOfflineTimer;
};
#endif
diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp
index 8f2a8917ba6..2d44ee3b955 100644
--- a/src/server/game/Groups/GroupMgr.cpp
+++ b/src/server/game/Groups/GroupMgr.cpp
@@ -109,6 +109,12 @@ Group* GroupMgr::GetGroupByGUID(ObjectGuid::LowType groupId) const
return nullptr;
}
+void GroupMgr::Update(uint32 diff)
+{
+ for (auto group : GroupStore)
+ group.second->Update(diff);
+}
+
void GroupMgr::AddGroup(Group* group)
{
GroupStore[group->GetLowGUID()] = group;
diff --git a/src/server/game/Groups/GroupMgr.h b/src/server/game/Groups/GroupMgr.h
index b1cb956e8ad..68d176c8038 100644
--- a/src/server/game/Groups/GroupMgr.h
+++ b/src/server/game/Groups/GroupMgr.h
@@ -41,6 +41,8 @@ public:
Group* GetGroupByDbStoreId(uint32 storageId) const;
void SetGroupDbStoreSize(uint32 newSize) { GroupDbStore.resize(newSize); }
+ void Update(uint32 diff);
+
void LoadGroups();
ObjectGuid::LowType GenerateGroupId();
void AddGroup(Group* group);
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 72c7cc5ffed..adcb3421ccf 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -848,6 +848,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
//pCurrChar->groupInfo.group->SendInit(this); // useless
group->SendUpdate();
group->ResetMaxEnchantingLevel();
+ if (group->GetLeaderGUID() == pCurrChar->GetGUID())
+ group->StopLeaderOfflineTimer();
}
// friend status
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index dafb08bd2ce..3c1de96e01b 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -548,16 +548,13 @@ void WorldSession::LogoutPlayer(bool save)
///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group.
_player->UninviteFromGroup();
- // remove player from the group if he is:
- // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected)
- if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket)
- _player->RemoveFromGroup();
-
//! Send update to group and reset stored max enchanting level
- if (_player->GetGroup())
+ if (Group* group = _player->GetGroup())
{
- _player->GetGroup()->SendUpdate();
- _player->GetGroup()->ResetMaxEnchantingLevel();
+ group->SendUpdate();
+ group->ResetMaxEnchantingLevel();
+ if (group->GetLeaderGUID() == _player->GetGUID())
+ group->StartLeaderOfflineTimer();
}
//! Broadcast a logout message to the player's friends
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index cb26d8a00bf..851072648a2 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -2402,6 +2402,9 @@ void World::Update(uint32 diff)
Player::DeleteOldCharacters();
}
+ sGroupMgr->Update(diff);
+ sWorldUpdateTime.RecordUpdateTimeDuration("UpdateGroupMgr");
+
sLFGMgr->Update(diff);
sWorldUpdateTime.RecordUpdateTimeDuration("UpdateLFGMgr");