diff options
| author | et65 <et65@ashbringer.fr> | 2015-05-19 02:55:53 +0100 |
|---|---|---|
| committer | et65 <et65@ashbringer.fr> | 2015-05-19 13:10:29 +0200 |
| commit | c6ab951025b0be3b0f64dc8bb0703d4aa8bdb003 (patch) | |
| tree | 721c10ff9d69f5c70b743e3fb4d87250dc479a06 /src/server/game/Groups | |
| parent | 7382c7d5d3ecfce7ae8d59390ba3ffa17eea81a9 (diff) | |
Core/PacketsIO: Implemented or updated most of party related packets.
Packets updated or implemented :
- SMSG_INSTANCE_INFO : updated
- CMSG_SAVE_CUF_PROFILES : updated
- SMSG_LOAD_CUF_PROFILES : updated
- SMSG_PARTY_COMMAND_RESULT : updated
- CMSG_PARTY_INVITE : updated
- SMSG_PARTY_INVITE : updated
- CMSG_PARTY_INVITE_RESPONSE : updated
- CMSG_PARTY_UNINVITE : updated
- SMSG_GROUP_UNINVITE : updated
- CMSG_LEAVE_GROUP : updated
- SMSG_GROUP_DECLINE : updated
- SMSG_GROUP_DESTROYED : updated
- CMSG_MINIMAP_PING : updated
- SMSG_MINIMAP_PING : updated
- CMSG_CONVERT_RAID : updated
- CMSG_SET_EVERYONE_IS_ASSISTANT
- CMSG_DO_READY_CHECK : updated
- CMSG_READY_CHECK_RESPONSE : updated
- SMSG_READY_CHECK_COMPLETED : updated
- SMSG_READY_CHECK_RESPONSE : updated
- SMSG_READY_CHECK_STARTED : updated
- CMSG_REQUEST_PARTY_JOIN_UPDATES : implemented (source : sniffs)
- CMSG_REQUEST_PARTY_MEMBER_STATE : updated
- SMSG_PARTY_MEMBER_STATE : updated
- SMSG_PARTY_UPDATE : updated
- CMSG_REQUEST_RAID_INFO : updated
- CMSG_INITIATE_ROLE_POLL : updated
- SMSG_ROLE_POLL_INFORM : updated
- CMSG_SET_ROLE : updated
- SMSG_ROLE_CHANGED_INFORM : updated
- CMSG_CHANGE_SUB_GROUP : updated
- CMSG_SWAP_SUB_GROUPS : implemented
- CMSG_SET_ASSISTANT_LEADER : updated
- CMSG_SET_PARTY_LEADER : updated
- SMSG_GROUP_NEW_LEADER : updated
- CMSG_CLEAR_RAID_MARKER : implemented
- SMSG_RAID_MARKERS_CHANGED : implemented
- CMSG_UPDATE_RAID_TARGET : updated
- SMSG_SEND_RAID_TARGET_UPDATE_ALL : updated
- SMSG_SEND_RAID_TARGET_UPDATE_SINGLE : updated
- CMSG_OPT_OUT_OF_LOOT : updated
- CMSG_SET_LOOT_METHOD : updated
About group update flags:
- Not sure they are use for now.
- Pets now have their group update flags.
- Pets'power is no send to client anymore.
- Changes about them are inspired from SMSG_PARTY_MEMBER_STATS parsing of WowPacketParser, but it seems this packet is not use anymore.
CHAT_MSG_RAID has been fixed.
About Ready check:
- Correctly implemented this function.
- An update function has been added to Group class, and to GroupMgr class in order to manage the ready check expiration (when 35 seconds were gone, players who have not answered must be reported as AFK)
About Raid markers:
- Old spell effect SPELL_EFFECT_SUMMON_OBJECT_SLOT3 has been renamed to SPELL_EFFECT_CHANGE_RAID_MARKER and implemented. I'm sure about that because raid markers spells are the only spells that have this effect type.
Source: WowPacketParser, and sniffs from official.
Diffstat (limited to 'src/server/game/Groups')
| -rw-r--r-- | src/server/game/Groups/Group.cpp | 451 | ||||
| -rw-r--r-- | src/server/game/Groups/Group.h | 153 | ||||
| -rw-r--r-- | src/server/game/Groups/GroupMgr.cpp | 7 | ||||
| -rw-r--r-- | src/server/game/Groups/GroupMgr.h | 2 |
4 files changed, 446 insertions, 167 deletions
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index f359e1eff57..fadf7e1970e 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -21,6 +21,7 @@ #include "WorldPacket.h" #include "WorldSession.h" #include "Player.h" +#include "Pet.h" #include "World.h" #include "ObjectMgr.h" #include "GroupMgr.h" @@ -35,6 +36,7 @@ #include "Util.h" #include "LFGMgr.h" #include "UpdateFieldFlags.h" +#include "PartyPackets.h" Roll::Roll(ObjectGuid _guid, LootItem const& li) : itemGUID(_guid), itemid(li.itemid), itemRandomPropId(li.randomPropertyId), itemRandomSuffix(li.randomSuffix), itemCount(li.count), @@ -55,11 +57,15 @@ Loot* Roll::getLoot() Group::Group() : m_leaderGuid(), m_leaderName(""), m_groupType(GROUPTYPE_NORMAL), m_dungeonDifficulty(DIFFICULTY_NORMAL), m_raidDifficulty(DIFFICULTY_NORMAL_RAID), m_legacyRaidDifficulty(DIFFICULTY_10_N), -m_bgGroup(NULL), m_bfGroup(NULL), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(), -m_masterLooterGuid(), m_subGroupsCounts(NULL), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0) +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_readyCheckStarted(false), m_readyCheckTimer(0), m_activeMarkers(0) { - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].Clear(); + + for (uint8 i = 0; i < RAID_MARKERS_COUNT; ++i) + m_markers[i] = nullptr; } Group::~Group() @@ -176,7 +182,7 @@ void Group::LoadGroupFromDB(Field* fields) m_looterGuid = ObjectGuid::Create<HighGuid::Player>(fields[2].GetUInt64()); m_lootThreshold = ItemQualities(fields[3].GetUInt8()); - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].SetRawValue(fields[4 + i].GetBinary()); m_groupType = GroupType(fields[12].GetUInt8()); @@ -199,7 +205,7 @@ void Group::LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uin member.guid = ObjectGuid::Create<HighGuid::Player>(guidLow); // skip non-existed member - if (!ObjectMgr::GetPlayerNameByGUID(member.guid, member.name)) + if (!ObjectMgr::GetPlayerNameAndClassByGUID(member.guid, member.name, member._class)) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER); stmt->setUInt64(0, guidLow); @@ -207,9 +213,10 @@ void Group::LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uin return; } - member.group = subgroup; - member.flags = memberFlags; - member.roles = roles; + member.group = subgroup; + member.flags = memberFlags; + member.roles = roles; + member.readyChecked = false; m_memberSlots.push_back(member); @@ -368,7 +375,7 @@ bool Group::AddMember(Player* player) bool groupFound = false; for (; subGroup < MAX_RAID_SUBGROUPS; ++subGroup) { - if (m_subGroupsCounts[subGroup] < MAXGROUPSIZE) + if (m_subGroupsCounts[subGroup] < MAX_GROUP_SIZE) { groupFound = true; break; @@ -380,11 +387,13 @@ bool Group::AddMember(Player* player) } MemberSlot member; - member.guid = player->GetGUID(); - member.name = player->GetName(); - member.group = subGroup; - member.flags = 0; - member.roles = 0; + member.guid = player->GetGUID(); + member.name = player->GetName(); + member._class = player->getClass(); + member.group = subGroup; + member.flags = 0; + member.roles = 0; + member.readyChecked = false; m_memberSlots.push_back(member); SubGroupCounterIncrease(subGroup); @@ -407,7 +416,7 @@ bool Group::AddMember(Player* player) if (!isRaidGroup()) // reset targetIcons for non-raid-groups { - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].Clear(); } @@ -455,7 +464,11 @@ bool Group::AddMember(Player* player) } } } + player->SetGroupUpdateFlag(GROUP_UPDATE_FULL); + if (Pet* pet = player->GetPet()) + pet->SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); + UpdatePlayerOutOfRange(player); // quest related GO state dependent from raid membership @@ -552,12 +565,6 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R player->GetSession()->SendPacket(&data); } - // Do we really need to send this opcode? - data.Initialize(SMSG_PARTY_UPDATE, 1+1+1+1+8+4+4+8); - data << uint8(0x10) << uint8(0) << uint8(0) << uint8(0); - data << m_guid << uint32(m_counter) << uint32(0) << uint64(0); - player->GetSession()->SendPacket(&data); - _homebindIfInstance(player); } @@ -644,7 +651,7 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R } } -void Group::ChangeLeader(ObjectGuid newLeaderGuid) +void Group::ChangeLeader(ObjectGuid newLeaderGuid, int8 partyIndex) { member_witerator slot = _getMemberWSlot(newLeaderGuid); @@ -707,9 +714,10 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid) m_leaderName = newLeader->GetName(); ToggleGroupMemberFlag(slot, MEMBER_FLAG_ASSISTANT, false); - WorldPacket data(SMSG_GROUP_NEW_LEADER, m_leaderName.size()+1); - data << slot->name; - BroadcastPacket(&data, true); + WorldPackets::Party::GroupNewLeader groupNewLeader; + groupNewLeader.Name = m_leaderName; + groupNewLeader.PartyIndex = partyIndex; + BroadcastPacket(groupNewLeader.Write(), true); } void Group::Disband(bool hideDestroy /* = false */) @@ -1491,45 +1499,38 @@ void Group::CountTheRoll(Rolls::iterator rollI) delete roll; } -void Group::SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid) +void Group::SetTargetIcon(uint8 symbol, ObjectGuid target, ObjectGuid changedBy, uint8 partyIndex) { - if (id >= TARGETICONCOUNT) + if (symbol >= TARGET_ICONS_COUNT) return; // clean other icons - if (!targetGuid.IsEmpty()) - for (int i = 0; i < TARGETICONCOUNT; ++i) - if (m_targetIcons[i] == targetGuid) - SetTargetIcon(i, ObjectGuid::Empty, ObjectGuid::Empty); + if (!target.IsEmpty()) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) + if (m_targetIcons[i] == target) + SetTargetIcon(i, ObjectGuid::Empty, changedBy, partyIndex); - m_targetIcons[id] = targetGuid; + m_targetIcons[symbol] = target; - WorldPacket data(SMSG_SEND_RAID_TARGET_UPDATE_SINGLE, (1+8+1+8)); - data << uint8(0); // set targets - data << whoGuid; - data << uint8(id); - data << targetGuid; - BroadcastPacket(&data, true); + WorldPackets::Party::SendRaidTargetUpdateSingle updateSingle; + updateSingle.PartyIndex = partyIndex; + updateSingle.Target = target; + updateSingle.ChangedBy = changedBy; + updateSingle.Symbol = symbol; + BroadcastPacket(updateSingle.Write(), true); } -void Group::SendTargetIconList(WorldSession* session) +void Group::SendTargetIconList(WorldSession* session, int8 partyIndex) { if (!session) return; - WorldPacket data(SMSG_SEND_RAID_TARGET_UPDATE_ALL, (1+TARGETICONCOUNT*9)); - data << uint8(1); // list targets + WorldPackets::Party::SendRaidTargetUpdateAll updateAll; + updateAll.PartyIndex = partyIndex; + for (uint8 i = 0; i < TARGET_ICONS_COUNT; i++) + updateAll.TargetIcons.insert(std::pair<uint8, ObjectGuid>(i, m_targetIcons[i])); - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) - { - if (m_targetIcons[i].IsEmpty()) - continue; - - data << uint8(i); - data << m_targetIcons[i]; - } - - session->SendPacket(&data); + session->SendPacket(updateAll.Write()); } void Group::SendUpdate() @@ -1556,56 +1557,79 @@ void Group::SendUpdateToPlayer(ObjectGuid playerGUID, MemberSlot* slot) slot = &(*witr); } - WorldPacket data(SMSG_PARTY_UPDATE, (1+1+1+1+1+4+8+4+4+(GetMembersCount()-1)*(13+8+1+1+1+1)+8+1+8+1+1+1+1)); - data << uint8(m_groupType); // group type (flags in 3.3) - data << uint8(slot->group); - data << uint8(slot->flags); - data << uint8(slot->roles); - if (isLFGGroup()) - { - data << uint8(sLFGMgr->GetState(m_guid) == lfg::LFG_STATE_FINISHED_DUNGEON ? 2 : 0); // FIXME - Dungeon save status? 2 = done - data << uint32(sLFGMgr->GetDungeon(m_guid)); - data << uint8(0); // 4.x new - } + WorldPackets::Party::PartyUpdate partyUpdate; - data << m_guid; - data << uint32(m_counter++); // 3.3, value increases every time this packet gets sent - data << uint32(GetMembersCount()-1); - for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) + partyUpdate.PartyType = m_groupType; + partyUpdate.PartyIndex = 0; + partyUpdate.PartyFlags = uint8(IsCreated()); + + partyUpdate.PartyGUID = m_guid; + partyUpdate.LeaderGUID = m_leaderGuid; + + partyUpdate.SequenceNum = m_counter++; // 3.3, value increases every time this packet gets sent + + partyUpdate.MyIndex = -1; + uint8 index = 0; + for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr, ++index) { if (slot->guid == citr->guid) - continue; + partyUpdate.MyIndex = index; Player* member = ObjectAccessor::FindConnectedPlayer(citr->guid); - uint8 onlineState = (member && !member->GetSession()->PlayerLogout()) ? MEMBER_STATUS_ONLINE : MEMBER_STATUS_OFFLINE; - onlineState = onlineState | ((isBGGroup() || isBFGroup()) ? MEMBER_STATUS_PVP : 0); + WorldPackets::Party::GroupPlayerInfos playerInfos; - data << citr->name; - data << citr->guid; // guid - data << uint8(onlineState); // online-state - data << uint8(citr->group); // groupid - data << uint8(citr->flags); // See enum GroupMemberFlags - data << uint8(citr->roles); // Lfg Roles + playerInfos.GUID = citr->guid; + playerInfos.Name = citr->name; + playerInfos.Class = citr->_class; + + playerInfos.Status = MEMBER_STATUS_OFFLINE; + if (member && member->GetSession() && !member->GetSession()->PlayerLogout()) + playerInfos.Status = MEMBER_STATUS_ONLINE | (isBGGroup() || isBFGroup() ? MEMBER_STATUS_PVP : 0); + + playerInfos.Subgroup = citr->group; // groupid + playerInfos.Flags = citr->flags; // See enum GroupMemberFlags + playerInfos.RolesAssigned = citr->roles; // Lfg Roles + + partyUpdate.PlayerList.push_back(playerInfos); } - data << m_leaderGuid; // leader guid + if (GetMembersCount() > 1) + { + // LootSettings + partyUpdate.LootSettings = boost::in_place(); + partyUpdate.LootSettings->Method = m_lootMethod; + partyUpdate.LootSettings->Threshold = m_lootThreshold; + partyUpdate.LootSettings->LootMaster = m_lootMethod == MASTER_LOOT ? m_masterLooterGuid : ObjectGuid::Empty; + + // Difficulty Settings + partyUpdate.DifficultySettings = boost::in_place(); + partyUpdate.DifficultySettings->DungeonDifficultyID = m_dungeonDifficulty; + partyUpdate.DifficultySettings->RaidDifficultyID = m_raidDifficulty; + partyUpdate.DifficultySettings->LegacyRaidDifficultyID = m_legacyRaidDifficulty; + } - if (GetMembersCount() - 1) + // LfgInfos + if (isLFGGroup()) { - data << uint8(m_lootMethod); // loot method + partyUpdate.LfgInfos = boost::in_place(); - if (m_lootMethod == MASTER_LOOT) - data << m_masterLooterGuid; // master looter guid - else - data << uint64(0); + partyUpdate.LfgInfos->Slot = sLFGMgr->GetDungeon(m_guid); + partyUpdate.LfgInfos->BootCount = 0; // new 6.x + partyUpdate.LfgInfos->Aborted = false; // new 6.x + + partyUpdate.LfgInfos->MyFlags = 0; // new 6.x + partyUpdate.LfgInfos->MyRandomSlot = 0; // new 6.x + + partyUpdate.LfgInfos->MyPartialClear = sLFGMgr->GetState(m_guid) == lfg::LFG_STATE_FINISHED_DUNGEON ? 2 : 0; // FIXME - Dungeon save status? 2 = done + partyUpdate.LfgInfos->MyGearDiff = 0.f; // new 6.x + partyUpdate.LfgInfos->MyFirstReward = false; // new 6.x - data << uint8(m_lootThreshold); // loot threshold - data << uint8(m_dungeonDifficulty); // Dungeon Difficulty - data << uint8(m_raidDifficulty); // Raid Difficulty + partyUpdate.LfgInfos->MyStrangerCount = 0; // new 6.x + partyUpdate.LfgInfos->MyKickVoteCount = 0; // new 6.x } - player->GetSession()->SendPacket(&data); + player->GetSession()->SendPacket(partyUpdate.Write()); } void Group::UpdatePlayerOutOfRange(Player* player) @@ -1613,15 +1637,15 @@ void Group::UpdatePlayerOutOfRange(Player* player) if (!player || !player->IsInWorld()) return; - WorldPacket data; - player->GetSession()->BuildPartyMemberStatsChangedPacket(player, &data); + WorldPackets::Party::PartyMemberStats packet; + packet.Initialize(player); Player* member; for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { member = itr->GetSource(); if (member && member != player && (!member->IsInMap(player) || !member->IsWithinDist(player, member->GetSightRange(), false))) - member->GetSession()->SendPacket(&data); + member->GetSession()->SendPacket(packet.Write()); } } @@ -1653,32 +1677,6 @@ void Group::BroadcastPacket(WorldPacket const* packet, bool ignorePlayersInBGRai } } -void Group::BroadcastReadyCheck(WorldPacket const* packet) -{ - for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* player = itr->GetSource(); - if (player && player->GetSession()) - if (IsLeader(player->GetGUID()) || IsAssistant(player->GetGUID())) - player->GetSession()->SendPacket(packet); - } -} - -void Group::OfflineReadyCheck() -{ - for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) - { - Player* player = ObjectAccessor::FindConnectedPlayer(citr->guid); - if (!player || !player->GetSession()) - { - WorldPacket data(SMSG_READY_CHECK_RESPONSE, 9); - data << citr->guid; - data << uint8(0); - BroadcastReadyCheck(&data); - } - } -} - bool Group::_setMembersGroup(ObjectGuid guid, uint8 group) { member_witerator slot = _getMemberWSlot(guid); @@ -1725,8 +1723,8 @@ void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) if (slot == m_memberSlots.end()) return; + uint8 prevSubGroup = slot->group; // Abort if the player is already in the target sub group - uint8 prevSubGroup = GetMemberGroup(guid); if (prevSubGroup == group) return; @@ -1758,7 +1756,6 @@ void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) else { // If player is in BG raid, it is possible that he is also in normal raid - and that normal raid is stored in m_originalGroup reference - prevSubGroup = player->GetOriginalSubGroup(); player->GetOriginalGroupRef().setSubGroup(group); } } @@ -1767,6 +1764,51 @@ void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) SendUpdate(); } +void Group::SwapMembersGroups(ObjectGuid firstGuid, ObjectGuid secondGuid) +{ + if (!isRaidGroup()) + return; + + member_witerator slots[2]; + slots[0] = _getMemberWSlot(firstGuid); + slots[1] = _getMemberWSlot(secondGuid); + if (slots[0] == m_memberSlots.end() || slots[1] == m_memberSlots.end()) + return; + + if (slots[0]->group == slots[1]->group) + return; + + uint8 tmp = slots[0]->group; + slots[0]->group = slots[1]->group; + slots[1]->group = tmp; + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + for (uint8 i = 0; i < 2; i++) + { + // Preserve new sub group in database for non-raid groups + if (!isBGGroup() && !isBFGroup()) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_SUBGROUP); + + stmt->setUInt8(0, slots[i]->group); + stmt->setUInt64(1, slots[i]->guid.GetCounter()); + + trans->Append(stmt); + } + + if (Player* player = ObjectAccessor::FindConnectedPlayer(slots[i]->guid)) + { + if (player->GetGroup() == this) + player->GetGroupRef().setSubGroup(slots[i]->group); + else + player->GetOriginalGroupRef().setSubGroup(slots[i]->group); + } + } + CharacterDatabase.CommitTransaction(trans); + + SendUpdate(); +} + // Retrieve the next Round-Roubin player for the group // // No update done if loot method is FFA. @@ -2262,9 +2304,167 @@ void Group::SetLfgRoles(ObjectGuid guid, uint8 roles) SendUpdate(); } +uint8 Group::GetLfgRoles(ObjectGuid guid) +{ + member_witerator slot = _getMemberWSlot(guid); + if (slot == m_memberSlots.end()) + return 0; + + return slot->roles; +} + +void Group::Update(uint32 diff) +{ + UpdateReadyCheck(diff); +} + +void Group::UpdateReadyCheck(uint32 diff) +{ + if (!m_readyCheckStarted) + return; + + m_readyCheckTimer -= diff; + if (m_readyCheckTimer <= 0) + EndReadyCheck(); +} + +void Group::StartReadyCheck(ObjectGuid starterGuid, int8 partyIndex, uint32 duration) +{ + if (m_readyCheckStarted) + return; + + member_witerator slot = _getMemberWSlot(starterGuid); + if (slot == m_memberSlots.end()) + return ; + + m_readyCheckStarted = true; + m_readyCheckTimer = duration; + + SetOfflineMembersReadyChecked(); + + SetMemberReadyChecked(&(*slot)); + + WorldPackets::Party::ReadyCheckStarted readyCheckStarted; + readyCheckStarted.PartyGUID = m_guid; + readyCheckStarted.PartyIndex = partyIndex; + readyCheckStarted.InitiatorGUID = starterGuid; + readyCheckStarted.Duration = duration; + BroadcastPacket(readyCheckStarted.Write(), false); +} + +void Group::EndReadyCheck(void) +{ + if (!m_readyCheckStarted) + return; + + m_readyCheckStarted = false; + m_readyCheckTimer = 0; + + ResetMemberReadyChecked(); + + WorldPackets::Party::ReadyCheckCompleted readyCheckCompleted; + readyCheckCompleted.PartyIndex = 0; + readyCheckCompleted.PartyGUID = m_guid; + BroadcastPacket(readyCheckCompleted.Write(), false); +} + +bool Group::IsReadyCheckCompleted(void) const +{ + for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) + if (!citr->readyChecked) + return false; + return true; +} + +void Group::SetMemberReadyCheck(ObjectGuid guid, bool ready) +{ + if (!m_readyCheckStarted) + return; + + member_witerator slot = _getMemberWSlot(guid); + if (slot != m_memberSlots.end()) + SetMemberReadyCheck(&(*slot), ready); +} + +void Group::SetMemberReadyCheck(MemberSlot* slot, bool ready) +{ + WorldPackets::Party::ReadyCheckResponse response; + response.PartyGUID = m_guid; + response.Player = slot->guid; + response.IsReady = ready; + BroadcastPacket(response.Write(), false); + + SetMemberReadyChecked(slot); +} + +void Group::SetOfflineMembersReadyChecked(void) +{ + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + { + Player* player = ObjectAccessor::FindConnectedPlayer(itr->guid); + if (!player || !player->GetSession()) + SetMemberReadyCheck(&(*itr), false); + } +} + +void Group::SetMemberReadyChecked(MemberSlot* slot) +{ + slot->readyChecked = true; + if (IsReadyCheckCompleted()) + EndReadyCheck(); +} + +void Group::ResetMemberReadyChecked(void) +{ + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + itr->readyChecked = false; +} + +void Group::AddRaidMarker(uint8 markerId, uint32 mapId, float positionX, float positionY, float positionZ, ObjectGuid transportGuid) +{ + if (markerId >= RAID_MARKERS_COUNT || m_markers[markerId]) + return; + + m_activeMarkers |= (1 << markerId); + m_markers[markerId] = Trinity::make_unique<RaidMarker>(mapId, positionX, positionY, positionZ, transportGuid); + SendRaidMarkersChanged(); +} + +void Group::DeleteRaidMarker(uint8 markerId) +{ + if (markerId > RAID_MARKERS_COUNT) + return; + + for (uint8 i = 0; i < RAID_MARKERS_COUNT; i++) + if (m_markers[i] && (markerId == i || markerId == RAID_MARKERS_COUNT)) + { + m_markers[i] = nullptr; + m_activeMarkers &= ~(1 << i); + } + + SendRaidMarkersChanged(); +} + +void Group::SendRaidMarkersChanged(WorldSession* session, int8 partyIndex) +{ + WorldPackets::Party::RaidMarkersChanged packet; + + packet.PartyIndex = partyIndex; + packet.ActiveMarkers = m_activeMarkers; + + for (uint8 i = 0; i < RAID_MARKERS_COUNT; i++) + if (m_markers[i]) + packet.RaidMarkers.push_back(m_markers[i].get()); + + if (session) + session->SendPacket(packet.Write()); + else + BroadcastPacket(packet.Write(), false); +} + bool Group::IsFull() const { - return isRaidGroup() ? (m_memberSlots.size() >= MAXRAIDSIZE) : (m_memberSlots.size() >= MAXGROUPSIZE); + return isRaidGroup() ? (m_memberSlots.size() >= MAX_RAID_SIZE) : (m_memberSlots.size() >= MAX_GROUP_SIZE); } bool Group::isLFGGroup() const @@ -2371,10 +2571,9 @@ bool Group::SameSubGroup(ObjectGuid guid1, MemberSlot const* slot2) const bool Group::HasFreeSlotSubGroup(uint8 subgroup) const { - return (m_subGroupsCounts && m_subGroupsCounts[subgroup] < MAXGROUPSIZE); + return (m_subGroupsCounts && m_subGroupsCounts[subgroup] < MAX_GROUP_SIZE); } - uint8 Group::GetMemberGroup(ObjectGuid guid) const { member_citerator mslot = _getMemberCSlot(guid); @@ -2522,3 +2721,15 @@ void Group::ToggleGroupMemberFlag(member_witerator slot, uint8 flag, bool apply) slot->flags &= ~flag; } +void Group::SetEveryoneIsAssistant(bool apply) +{ + if (apply) + m_groupType = GroupType(m_groupType | GROUPTYPE_EVERYONE_ASSISTANT); + else + m_groupType = GroupType(m_groupType & ~GROUPTYPE_EVERYONE_ASSISTANT); + + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + ToggleGroupMemberFlag(itr, MEMBER_FLAG_ASSISTANT, apply); + + SendUpdate(); +} diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 4154f31a410..e14ca6c976b 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -38,10 +38,14 @@ class WorldSession; struct MapEntry; -#define MAXGROUPSIZE 5 -#define MAXRAIDSIZE 40 -#define MAX_RAID_SUBGROUPS MAXRAIDSIZE/MAXGROUPSIZE -#define TARGETICONCOUNT 8 +#define MAX_GROUP_SIZE 5 +#define MAX_RAID_SIZE 40 +#define MAX_RAID_SUBGROUPS MAX_RAID_SIZE / MAX_GROUP_SIZE + +#define TARGET_ICONS_COUNT 8 +#define RAID_MARKERS_COUNT 8 + +#define READYCHECK_DURATION 35000 enum RollVote { @@ -81,50 +85,59 @@ enum GroupMemberAssignment enum GroupType { - GROUPTYPE_NORMAL = 0x00, - GROUPTYPE_BG = 0x01, - GROUPTYPE_RAID = 0x02, - GROUPTYPE_BGRAID = GROUPTYPE_BG | GROUPTYPE_RAID, // mask - GROUPTYPE_LFG_RESTRICTED = 0x04, // Script_HasLFGRestrictions() - GROUPTYPE_LFG = 0x08, + GROUPTYPE_NORMAL = 0x00, + GROUPTYPE_BG = 0x01, + GROUPTYPE_RAID = 0x02, + GROUPTYPE_BGRAID = GROUPTYPE_BG | GROUPTYPE_RAID, // mask + GROUPTYPE_LFG_RESTRICTED = 0x04, // Script_HasLFGRestrictions() + GROUPTYPE_LFG = 0x08, + GROUPTYPE_EVERYONE_ASSISTANT = 0x40, // Script_IsEveryoneAssistant() (4.x) // 0x10, leave/change group?, I saw this flag when leaving group and after leaving BG while in group // GROUPTYPE_ONE_PERSON_PARTY = 0x20, 4.x Script_IsOnePersonParty() - // GROUPTYPE_EVERYONE_ASSISTANT = 0x40 4.x Script_IsEveryoneAssistant() }; enum GroupUpdateFlags { GROUP_UPDATE_FLAG_NONE = 0x00000000, // nothing - GROUP_UPDATE_FLAG_STATUS = 0x00000001, // uint16 (GroupMemberStatusFlag) - GROUP_UPDATE_FLAG_CUR_HP = 0x00000002, // uint32 (HP) - GROUP_UPDATE_FLAG_MAX_HP = 0x00000004, // uint32 (HP) - GROUP_UPDATE_FLAG_POWER_TYPE = 0x00000008, // uint8 (PowerType) - GROUP_UPDATE_FLAG_CUR_POWER = 0x00000010, // int16 (power value) - GROUP_UPDATE_FLAG_MAX_POWER = 0x00000020, // int16 (power value) - GROUP_UPDATE_FLAG_LEVEL = 0x00000040, // uint16 (level value) - GROUP_UPDATE_FLAG_ZONE = 0x00000080, // uint16 (zone id) - GROUP_UPDATE_FLAG_UNK100 = 0x00000100, // int16 (unk) - GROUP_UPDATE_FLAG_POSITION = 0x00000200, // uint16 (x), uint16 (y), uint16 (z) - GROUP_UPDATE_FLAG_AURAS = 0x00000400, // uint8 (unk), uint64 (mask), uint32 (count), for each bit set: uint32 (spell id) + uint16 (AuraFlags) (if has flags Scalable -> 3x int32 (bps)) - GROUP_UPDATE_FLAG_PET_GUID = 0x00000800, // uint64 (pet guid) - GROUP_UPDATE_FLAG_PET_NAME = 0x00001000, // cstring (name, NULL terminated string) - GROUP_UPDATE_FLAG_PET_MODEL_ID = 0x00002000, // uint16 (model id) - GROUP_UPDATE_FLAG_PET_CUR_HP = 0x00004000, // uint32 (HP) - GROUP_UPDATE_FLAG_PET_MAX_HP = 0x00008000, // uint32 (HP) - GROUP_UPDATE_FLAG_PET_POWER_TYPE = 0x00010000, // uint8 (PowerType) - GROUP_UPDATE_FLAG_PET_CUR_POWER = 0x00020000, // uint16 (power value) - GROUP_UPDATE_FLAG_PET_MAX_POWER = 0x00040000, // uint16 (power value) - GROUP_UPDATE_FLAG_PET_AURAS = 0x00080000, // [see GROUP_UPDATE_FLAG_AURAS] - GROUP_UPDATE_FLAG_VEHICLE_SEAT = 0x00100000, // int32 (vehicle seat id) - GROUP_UPDATE_FLAG_PHASE = 0x00200000, // int32 (unk), uint32 (phase count), for (count) uint16(phaseId) - - GROUP_UPDATE_PET = GROUP_UPDATE_FLAG_PET_GUID | GROUP_UPDATE_FLAG_PET_NAME | GROUP_UPDATE_FLAG_PET_MODEL_ID | - GROUP_UPDATE_FLAG_PET_CUR_HP | GROUP_UPDATE_FLAG_PET_MAX_HP | GROUP_UPDATE_FLAG_PET_POWER_TYPE | - GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER | GROUP_UPDATE_FLAG_PET_AURAS, // all pet flags - GROUP_UPDATE_FULL = GROUP_UPDATE_FLAG_STATUS | GROUP_UPDATE_FLAG_CUR_HP | GROUP_UPDATE_FLAG_MAX_HP | - GROUP_UPDATE_FLAG_POWER_TYPE | GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER | - GROUP_UPDATE_FLAG_LEVEL | GROUP_UPDATE_FLAG_ZONE | GROUP_UPDATE_FLAG_POSITION | - GROUP_UPDATE_FLAG_AURAS | GROUP_UPDATE_PET | GROUP_UPDATE_FLAG_PHASE // all known flags, except UNK100 and VEHICLE_SEAT + GROUP_UPDATE_FLAG_UNK704 = 0x00000001, // uint8[2] (unk) + GROUP_UPDATE_FLAG_STATUS = 0x00000002, // uint16 (GroupMemberStatusFlag) + GROUP_UPDATE_FLAG_POWER_TYPE = 0x00000004, // uint8 (PowerType) + GROUP_UPDATE_FLAG_UNK322 = 0x00000008, // uint16 (unk) + GROUP_UPDATE_FLAG_CUR_HP = 0x00000010, // uint32 (HP) + GROUP_UPDATE_FLAG_MAX_HP = 0x00000020, // uint32 (max HP) + GROUP_UPDATE_FLAG_CUR_POWER = 0x00000040, // int16 (power value) + GROUP_UPDATE_FLAG_MAX_POWER = 0x00000080, // int16 (max power value) + GROUP_UPDATE_FLAG_LEVEL = 0x00000100, // uint16 (level value) + GROUP_UPDATE_FLAG_UNK200000 = 0x00000200, // int16 (unk) + GROUP_UPDATE_FLAG_ZONE = 0x00000400, // uint16 (zone id) + GROUP_UPDATE_FLAG_UNK2000000 = 0x00000800, // int16 (unk) + GROUP_UPDATE_FLAG_UNK4000000 = 0x00001000, // int32 (unk) + GROUP_UPDATE_FLAG_POSITION = 0x00002000, // uint16 (x), uint16 (y), uint16 (z) + GROUP_UPDATE_FLAG_VEHICLE_SEAT = 0x00104000, // int32 (vehicle seat id) + GROUP_UPDATE_FLAG_AURAS = 0x00008000, // uint8 (unk), uint64 (mask), uint32 (count), for each bit set: uint32 (spell id) + uint16 (AuraFlags) (if has flags Scalable -> 3x int32 (bps)) + GROUP_UPDATE_FLAG_PET = 0x00010000, // complex (pet) + GROUP_UPDATE_FLAG_PHASE = 0x00020000, // int32 (unk), uint32 (phase count), for (count) uint16(phaseId) + + GROUP_UPDATE_FULL = GROUP_UPDATE_FLAG_UNK704 | GROUP_UPDATE_FLAG_STATUS | GROUP_UPDATE_FLAG_POWER_TYPE | + GROUP_UPDATE_FLAG_UNK322 | GROUP_UPDATE_FLAG_CUR_HP | GROUP_UPDATE_FLAG_MAX_HP | + GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER | GROUP_UPDATE_FLAG_LEVEL | + GROUP_UPDATE_FLAG_UNK200000 | GROUP_UPDATE_FLAG_ZONE | GROUP_UPDATE_FLAG_UNK2000000 | + GROUP_UPDATE_FLAG_UNK4000000 | GROUP_UPDATE_FLAG_POSITION | GROUP_UPDATE_FLAG_VEHICLE_SEAT | + GROUP_UPDATE_FLAG_AURAS | GROUP_UPDATE_FLAG_PET | GROUP_UPDATE_FLAG_PHASE // all known flags +}; + +enum GroupUpdatePetFlags +{ + GROUP_UPDATE_FLAG_PET_NONE = 0x00000000, // nothing + GROUP_UPDATE_FLAG_PET_GUID = 0x00000001, // ObjectGuid (pet guid) + GROUP_UPDATE_FLAG_PET_NAME = 0x00000002, // cstring (name, NULL terminated string) + GROUP_UPDATE_FLAG_PET_MODEL_ID = 0x00000004, // uint16 (model id) + GROUP_UPDATE_FLAG_PET_CUR_HP = 0x00000008, // uint32 (HP) + GROUP_UPDATE_FLAG_PET_MAX_HP = 0x00000010, // uint32 (max HP) + GROUP_UPDATE_FLAG_PET_AURAS = 0x00000020, // [see GROUP_UPDATE_FLAG_AURAS] + + GROUP_UPDATE_PET_FULL = GROUP_UPDATE_FLAG_PET_GUID | GROUP_UPDATE_FLAG_PET_NAME | GROUP_UPDATE_FLAG_PET_MODEL_ID | + GROUP_UPDATE_FLAG_PET_CUR_HP | GROUP_UPDATE_FLAG_PET_MAX_HP | GROUP_UPDATE_FLAG_PET_AURAS // all pet flags }; class Roll : public LootValidatorRef @@ -160,6 +173,18 @@ struct InstanceGroupBind InstanceGroupBind() : save(NULL), perm(false) { } }; +struct RaidMarker +{ + WorldLocation Location; + ObjectGuid TransportGUID; + + RaidMarker(uint32 mapId, float positionX, float positionY, float positionZ, ObjectGuid transportGuid = ObjectGuid::Empty) + { + Location.WorldRelocate(mapId, positionX, positionY, positionZ); + TransportGUID = transportGuid; + } +}; + /** request member stats checken **/ /// @todo uninvite people that not accepted invite class Group @@ -169,9 +194,11 @@ class Group { ObjectGuid guid; std::string name; + uint8 _class; uint8 group; uint8 flags; uint8 roles; + bool readyChecked; }; typedef std::list<MemberSlot> MemberSlotList; typedef MemberSlotList::const_iterator member_citerator; @@ -197,7 +224,7 @@ class Group bool AddLeaderInvite(Player* player); 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); + void ChangeLeader(ObjectGuid guid, int8 partyIndex = 0); void SetLootMethod(LootMethod method); void SetLooterGuid(ObjectGuid guid); void SetMasterLooterGuid(ObjectGuid guid); @@ -205,6 +232,31 @@ class Group void SetLootThreshold(ItemQualities threshold); void Disband(bool hideDestroy = false); void SetLfgRoles(ObjectGuid guid, uint8 roles); + uint8 GetLfgRoles(ObjectGuid guid); + void SetEveryoneIsAssistant(bool apply); + + // Update + void Update(uint32 diff); + void UpdateReadyCheck(uint32 diff); + + // Ready check + void StartReadyCheck(ObjectGuid starterGuid, int8 partyIndex, uint32 duration = READYCHECK_DURATION); + void EndReadyCheck(); + + bool IsReadyCheckStarted(void) const { return m_readyCheckStarted; } + bool IsReadyCheckCompleted(void) const; + + void SetOfflineMembersReadyChecked(void); + void SetMemberReadyCheck(ObjectGuid guid, bool ready); + void SetMemberReadyCheck(MemberSlot* slot, bool ready); + + void SetMemberReadyChecked(MemberSlot* slot); + void ResetMemberReadyChecked(void); + + // Raid Markers + void AddRaidMarker(uint8 markerId, uint32 mapId, float positionX, float positionY, float positionZ, ObjectGuid transportGuid = ObjectGuid::Empty); + void DeleteRaidMarker(uint8 markerId); + void SendRaidMarkersChanged(WorldSession* session = nullptr, int8 partyIndex = 0); // properties accessories bool IsFull() const; @@ -254,7 +306,8 @@ class Group GroupJoinBattlegroundResult CanJoinBattlegroundQueue(Battleground const* bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot, ObjectGuid& errorGuid); void ChangeMembersGroup(ObjectGuid guid, uint8 group); - void SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid); + void SwapMembersGroups(ObjectGuid firstGuid, ObjectGuid secondGuid); + void SetTargetIcon(uint8 symbol, ObjectGuid target, ObjectGuid changedBy, uint8 partyIndex); void SetGroupMemberFlag(ObjectGuid guid, bool apply, GroupMemberFlags flag); void RemoveUniqueGroupMemberFlag(GroupMemberFlags flag); @@ -269,7 +322,7 @@ class Group // -no description- //void SendInit(WorldSession* session); - void SendTargetIconList(WorldSession* session); + void SendTargetIconList(WorldSession* session, int8 partyIndex = 0); void SendUpdate(); void SendUpdateToPlayer(ObjectGuid playerGUID, MemberSlot* slot = NULL); void UpdatePlayerOutOfRange(Player* player); @@ -290,8 +343,6 @@ class Group void BroadcastPacket(WorldPacket const* packet, bool ignorePlayersInBGRaid, int group = -1, ObjectGuid ignoredPlayer = ObjectGuid::Empty); void BroadcastAddonMessagePacket(WorldPacket const* packet, const std::string& prefix, bool ignorePlayersInBGRaid, int group = -1, ObjectGuid ignore = ObjectGuid::Empty); - void BroadcastReadyCheck(WorldPacket const* packet); - void OfflineReadyCheck(); /*********************************************************/ /*** LOOT SYSTEM ***/ @@ -351,7 +402,7 @@ class Group Difficulty m_legacyRaidDifficulty; Battleground* m_bgGroup; Battlefield* m_bfGroup; - ObjectGuid m_targetIcons[TARGETICONCOUNT]; + ObjectGuid m_targetIcons[TARGET_ICONS_COUNT]; LootMethod m_lootMethod; ItemQualities m_lootThreshold; ObjectGuid m_looterGuid; @@ -363,5 +414,13 @@ class 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) + + // Ready Check + bool m_readyCheckStarted; + int32 m_readyCheckTimer; + + // Raid markers + std::array<std::unique_ptr<RaidMarker>, RAID_MARKERS_COUNT> m_markers; + uint32 m_activeMarkers; }; #endif diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp index f0c764e7269..7fb239cec48 100644 --- a/src/server/game/Groups/GroupMgr.cpp +++ b/src/server/game/Groups/GroupMgr.cpp @@ -233,3 +233,10 @@ void GroupMgr::LoadGroups() TC_LOG_INFO("server.loading", ">> Loaded %u group-instance saves in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } } + +void GroupMgr::Update(uint32 diff) +{ + for (GroupContainer::iterator itr = GroupStore.begin(); itr != GroupStore.end(); itr++) + if (itr->second) + itr->second->Update(diff); +} diff --git a/src/server/game/Groups/GroupMgr.h b/src/server/game/Groups/GroupMgr.h index 6aafe77432c..2fdd6d978e9 100644 --- a/src/server/game/Groups/GroupMgr.h +++ b/src/server/game/Groups/GroupMgr.h @@ -50,6 +50,8 @@ public: void AddGroup(Group* group); void RemoveGroup(Group* group); + void Update(uint32 diff); + protected: ObjectGuid::LowType NextGroupId; |
