diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/server/game/Battlegrounds/Battleground.cpp | 7 | ||||
| -rwxr-xr-x | src/server/game/Chat/Commands/Level3.cpp | 3 | ||||
| -rwxr-xr-x | src/server/game/DungeonFinding/LFGMgr.cpp | 4 | ||||
| -rwxr-xr-x | src/server/game/Entities/Player/Player.cpp | 46 | ||||
| -rwxr-xr-x | src/server/game/Entities/Player/Player.h | 2 | ||||
| -rwxr-xr-x | src/server/game/Groups/Group.cpp | 575 | ||||
| -rwxr-xr-x | src/server/game/Groups/Group.h | 27 | ||||
| -rwxr-xr-x | src/server/game/Server/Protocol/Handlers/GroupHandler.cpp | 134 |
8 files changed, 358 insertions, 440 deletions
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 39f1291624f..9a4a23b6878 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -1203,7 +1203,7 @@ void Battleground::AddOrSetPlayerToCorrectBgGroup(Player *player, uint32 team) { group = new Group; SetBgRaid(team, group); - group->Create(playerGuid, player->GetName()); + group->Create(player); } else // raid already exist { @@ -1214,10 +1214,13 @@ void Battleground::AddOrSetPlayerToCorrectBgGroup(Player *player, uint32 team) } else { - group->AddMember(playerGuid, player->GetName()); + group->AddMember(player); if (Group* originalGroup = player->GetOriginalGroup()) if (originalGroup->IsLeader(playerGuid)) + { group->ChangeLeader(playerGuid); + group->SendUpdate(); + } } } } diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp index 649e1ce199f..6625d954127 100755 --- a/src/server/game/Chat/Commands/Level3.cpp +++ b/src/server/game/Chat/Commands/Level3.cpp @@ -4634,7 +4634,10 @@ bool ChatHandler::HandleGroupLeaderCommand(const char *args) if (GetPlayerGroupAndGUIDByName(cname, plr, group, guid)) if (group && group->GetLeaderGUID() != guid) + { group->ChangeLeader(guid); + group->SendUpdate(); + } return true; } diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index d7a329737a6..f38a35602fd 100755 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -1345,14 +1345,14 @@ void LFGMgr::UpdateProposal(uint32 proposalId, const uint64& guid, bool accept) if (!grp) { grp = new Group(); - grp->Create(pguid, plr->GetName()); + grp->Create(plr); grp->ConvertToLFG(); uint64 gguid = grp->GetGUID(); SetState(gguid, LFG_STATE_PROPOSAL); sObjectMgr->AddGroup(grp); } else if (group != grp) - grp->AddMember(pguid, plr->GetName()); + grp->AddMember(plr); // Update timers uint8 role = GetRoles(pguid); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 835d73bae51..752572151ef 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7214,7 +7214,7 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) // group update if (GetGroup()) - SetGroupUpdateFlag(GROUP_UPDATE_FLAG_ZONE); + SetGroupUpdateFlag(GROUP_UPDATE_FULL); UpdateZoneDependentAuras(newZone); } @@ -17785,50 +17785,26 @@ void Player::SendSavedInstances() } /// convert the player's binds to the group -void Player::ConvertInstancesToGroup(Player *player, Group *group, uint64 player_guid) +void Player::ConvertInstancesToGroup(Player *player, Group *group, bool switchLeader) { - bool has_binds = false; - bool has_solo = false; - - if (player) - { - player_guid = player->GetGUID(); - if (!group) - group = player->GetGroup(); - } - ASSERT(player_guid); - // copy all binds to the group, when changing leader it's assumed the character // will not have any solo binds - if (player) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { - for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) + for (BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();) { - for (BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();) + group->BindToInstance(itr->second.save, itr->second.perm, false); + // permanent binds are not removed + if (switchLeader && !itr->second.perm) { - has_binds = true; - if (group) - group->BindToInstance(itr->second.save, itr->second.perm, true); - // permanent binds are not removed - if (!itr->second.perm) - { - // increments itr in call - player->UnbindInstance(itr, Difficulty(i), true); - has_solo = true; - } - else - ++itr; + // increments itr in call + player->UnbindInstance(itr, Difficulty(i), false); } + else + ++itr; } } - - // if the player's not online we don't know what binds it has - if (!player || !group || has_binds) - CharacterDatabase.PExecute("INSERT INTO group_instance SELECT guid, instance, permanent FROM character_instance WHERE guid = '%u'", GUID_LOPART(player_guid)); - // the following should not get executed when changing leaders - if (!player || has_solo) - CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND permanent = 0", GUID_LOPART(player_guid)); } bool Player::Satisfy(AccessRequirement const* ar, uint32 target_map, bool report) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 4d445464a41..aacfe1a31ee 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2305,7 +2305,7 @@ class Player : public Unit, public GridObject<Player> bool HasPendingBind() const { return _pendingBind != NULL; } void SendRaidInfo(); void SendSavedInstances(); - static void ConvertInstancesToGroup(Player *player, Group *group = NULL, uint64 player_guid = 0); + static void ConvertInstancesToGroup(Player *player, Group *group, bool switchLeader); bool Satisfy(AccessRequirement const* ar, uint32 target_map, bool report = false); bool CheckInstanceLoginValid(); bool CheckInstanceCount(uint32 instanceId) const diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index b798c4df2a6..fe0592777a4 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -92,12 +92,13 @@ Group::~Group() delete[] m_subGroupsCounts; } -bool Group::Create(const uint64 &guid, const char * name) +bool Group::Create(Player *leader) { + uint64 leaderGuid = leader->GetGUID(); uint32 lowguid = sObjectMgr->GenerateLowGuid(HIGHGUID_GROUP); m_guid = MAKE_NEW_GUID(lowguid, 0, HIGHGUID_GROUP); - m_leaderGuid = guid; - m_leaderName = name; + m_leaderGuid = leaderGuid; + m_leaderName = leader->GetName(); m_groupType = isBGGroup() ? GROUPTYPE_BGRAID : GROUPTYPE_NORMAL; @@ -106,37 +107,29 @@ bool Group::Create(const uint64 &guid, const char * name) m_lootMethod = GROUP_LOOT; m_lootThreshold = ITEM_QUALITY_UNCOMMON; - m_looterGuid = guid; + m_looterGuid = leaderGuid; m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL; m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; + if (!isBGGroup()) { - Player *leader = sObjectMgr->GetPlayer(guid); - if (leader) - { - m_dungeonDifficulty = leader->GetDungeonDifficulty(); - m_raidDifficulty = leader->GetRaidDifficulty(); - } - - Player::ConvertInstancesToGroup(leader, this, guid); - - if (!AddMember(guid, name)) - return false; + m_dungeonDifficulty = leader->GetDungeonDifficulty(); + m_raidDifficulty = leader->GetRaidDifficulty(); // store group in database - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->PAppend("DELETE FROM groups WHERE guid ='%u'", lowguid); - trans->PAppend("DELETE FROM group_member WHERE guid = %u OR memberGuid = %u", lowguid, GUID_LOPART(guid)); - trans->PAppend("INSERT INTO group_member (guid, memberGuid, subgroup) VALUES (%u, %u, 0)", lowguid, GUID_LOPART(guid)); - trans->PAppend("INSERT INTO groups (guid,leaderGuid,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,groupType,difficulty,raiddifficulty) " + CharacterDatabase.PExecute("INSERT INTO groups (guid,leaderGuid,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,groupType,difficulty,raiddifficulty) " "VALUES ('%u','%u','%u','%u','%u','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','%u','%u','%u')", lowguid, GUID_LOPART(m_leaderGuid), uint32(m_lootMethod), - GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], m_targetIcons[7], uint8(m_groupType), uint32(m_dungeonDifficulty), m_raidDifficulty); + GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], + m_targetIcons[7], uint8(m_groupType), uint32(m_dungeonDifficulty), m_raidDifficulty); + + ASSERT(AddMember(leader)); // If the leader can't be added to a new group because it appears full, something is clearly wrong. + + Player::ConvertInstancesToGroup(leader, this, false); - CharacterDatabase.CommitTransaction(trans); } - else if (!AddMember(guid, name)) + else if (!AddMember(leader)) return false; return true; @@ -315,15 +308,66 @@ Player* Group::GetInvited(const std::string& name) const return NULL; } -bool Group::AddMember(const uint64 &guid, const char* name) +bool Group::AddMember(Player *player) { - if (!_addMember(guid, name)) - return false; + // Get first not-full group + uint8 subGroup = 0; + if (m_subGroupsCounts) + { + bool groupFound = false; + for (; subGroup < MAX_RAID_SUBGROUPS; ++subGroup) + { + if (m_subGroupsCounts[subGroup] < MAXGROUPSIZE) + { + groupFound = true; + break; + } + } + // We are raid group and no one slot is free + if (!groupFound) + return false; + } + + MemberSlot member; + member.guid = player->GetGUID(); + member.name = player->GetName(); + member.group = subGroup; + member.flags = 0; + member.roles = 0; + m_memberSlots.push_back(member); + + SubGroupCounterIncrease(subGroup); + + if (player) + { + player->SetGroupInvite(NULL); + if (player->GetGroup() && isBGGroup()) //if player is in group and he is being added to BG raid group, then call SetBattlegroundRaid() + player->SetBattlegroundRaid(this, subGroup); + else if (player->GetGroup()) //if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup() + player->SetOriginalGroup(this, subGroup); + else //if player is not in group, then call set group + player->SetGroup(this, subGroup); + + // if the same group invites the player back, cancel the homebind timer + InstanceGroupBind *bind = GetBoundInstance(player); + if (bind && bind->save->GetInstanceId() == player->GetInstanceId()) + player->m_InstanceValid = true; + } + + if (!isRaidGroup()) // reset targetIcons for non-raid-groups + { + for (uint8 i = 0; i < TARGETICONCOUNT; ++i) + m_targetIcons[i] = 0; + } + + // insert into the table if we're not a battleground group + if (!isBGGroup()) + CharacterDatabase.PExecute("INSERT INTO group_member (guid, memberGuid, memberFlags, subgroup, roles) VALUES(%u, %u, %u, %u, %u)", + GUID_LOPART(m_guid), GUID_LOPART(member.guid), member.flags, member.group, member.roles); SendUpdate(); - sScriptMgr->OnGroupAddMember(this, guid); + sScriptMgr->OnGroupAddMember(this, player->GetGUID()); - Player *player = sObjectMgr->GetPlayer(guid); if (player) { if (!IsLeader(player->GetGUID()) && !isBGGroup()) @@ -367,20 +411,30 @@ uint32 Group::RemoveMember(const uint64 &guid, const RemoveMethod &method /* = G sScriptMgr->OnGroupRemoveMember(this, guid, method, kicker, reason); - // Lfg group vote kick handled in scripts + // LFG group vote kick handled in scripts if (isLFGGroup() && method == GROUP_REMOVEMETHOD_KICK) return m_memberSlots.size(); // remove member and change leader (if need) only if strong more 2 members _before_ member remove (BG allow 1 member group) if (GetMembersCount() > (isBGGroup() ? 1u : 2u)) { - bool leaderChanged = _removeMember(guid); - - if (Player *player = sObjectMgr->GetPlayer(guid)) + Player *player = sObjectMgr->GetPlayer(guid); + if (player) { - // quest related GO state dependent from raid membership - if (isRaidGroup()) + // Battleground group handling + if (isBGGroup()) + player->RemoveFromBattlegroundRaid(); + else + // Regular group + { + if (player->GetOriginalGroup() == this) + player->SetOriginalGroup(NULL); + else + player->SetGroup(NULL); + + // quest related GO state dependent from raid membership player->UpdateForQuestWorldObjects(); + } WorldPacket data; @@ -390,31 +444,69 @@ uint32 Group::RemoveMember(const uint64 &guid, const RemoveMethod &method /* = G player->GetSession()->SendPacket(&data); } - //we already removed player from group and in player->GetGroup() is his original group! - if (Group* group = player->GetGroup()) - group->SendUpdate(); - else - { - data.Initialize(SMSG_GROUP_LIST, 1+1+1+1+8+4+4+8); - data << uint8(0x10) << uint8(0) << uint8(0) << uint8(0); - data << uint64(m_guid) << uint32(m_counter) << uint32(0) << uint64(0); - player->GetSession()->SendPacket(&data); - } + // Do we really need to send this opcode? + data.Initialize(SMSG_GROUP_LIST, 1+1+1+1+8+4+4+8); + data << uint8(0x10) << uint8(0) << uint8(0) << uint8(0); + data << uint64(m_guid) << uint32(m_counter) << uint32(0) << uint64(0); + player->GetSession()->SendPacket(&data); _homebindIfInstance(player); } - if (leaderChanged) + // Remove player from group in DB + CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid=%u", GUID_LOPART(guid)); + + // Reevaluate group enchanter if the leaving player had enchanting skill or the player is offline + if (player && player->GetSkillValue(SKILL_ENCHANTING) || !player) + ResetMaxEnchantingLevel(); + + // Remove player from loot rolls + for (Rolls::iterator it = RollId.begin(); it != RollId.end(); ++it) + { + Roll* roll = *it; + Roll::PlayerVote::iterator itr2 = roll->playerVote.find(guid); + if (itr2 == roll->playerVote.end()) + continue; + + if (itr2->second == GREED || itr2->second == DISENCHANT) + --roll->totalGreed; + else if (itr2->second == NEED) + --roll->totalNeed; + else if (itr2->second == PASS) + --roll->totalPass; + + if (itr2->second != NOT_VALID) + --roll->totalPlayersRolling; + + roll->playerVote.erase(itr2); + + CountRollVote(guid, roll->itemGUID, GetMembersCount()-1, MAX_ROLL_TYPE); + } + + // Update subgroups + member_witerator slot = _getMemberWSlot(guid); + if (slot != m_memberSlots.end()) { - WorldPacket data(SMSG_GROUP_SET_LEADER, (m_memberSlots.front().name.size()+1)); - data << m_memberSlots.front().name; - BroadcastPacket(&data, true); + SubGroupCounterDecrease(slot->group); + m_memberSlots.erase(slot); + } + + // Pick new leader if necessary + if (m_leaderGuid == guid) + { + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + { + if (sObjectMgr->GetPlayer(itr->guid)) + { + ChangeLeader(itr->guid); + break; + } + } } SendUpdate(); - ResetMaxEnchantingLevel(); } - // if group before remove <= 2 disband it + // If group size before player removal <= 2 then disband it else Disband(); @@ -423,17 +515,54 @@ uint32 Group::RemoveMember(const uint64 &guid, const RemoveMethod &method /* = G void Group::ChangeLeader(const uint64 &guid) { - member_citerator slot = _getMemberCSlot(guid); + member_witerator slot = _getMemberWSlot(guid); if (slot == m_memberSlots.end()) return; - _setLeader(guid); + Player *player = sObjectMgr->GetPlayer(slot->guid); - WorldPacket data(SMSG_GROUP_SET_LEADER, slot->name.size()+1); + // Don't allow switching leader to offline players + if (!player) + return; + + sScriptMgr->OnGroupChangeLeader(this, m_leaderGuid, guid); + + if (!isBGGroup()) + { + // Remove the groups permanent instance bindings + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) + { + for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end();) + { + if (itr->second.perm) + { + itr->second.save->RemoveGroup(this); + m_boundInstances[i].erase(itr++); + } + else + ++itr; + } + } + + // Same in the database + CharacterDatabase.PExecute("DELETE FROM group_instance WHERE guid=%u AND (permanent = 1 OR instance IN (SELECT instance FROM character_instance WHERE guid = '%u'))", + GUID_LOPART(m_guid), player->GetGUIDLow()); + + // Copy the permanent binds from the new leader to the group + Player::ConvertInstancesToGroup(player, this, true); + + // update the group leader + CharacterDatabase.PExecute("UPDATE groups SET leaderGuid='%u' WHERE guid='%u'", player->GetGUIDLow(), GUID_LOPART(m_guid)); + } + + m_leaderGuid = player->GetGUID(); + m_leaderName = player->GetName(); + ToggleGroupMemberFlag(slot, MEMBER_FLAG_ASSISTANT, false); + + WorldPacket data(SMSG_GROUP_SET_LEADER, m_leaderName.size()+1); data << slot->name; BroadcastPacket(&data, true); - SendUpdate(); } void Group::Disband(bool hideDestroy /* = false */) @@ -1203,199 +1332,6 @@ void Group::OfflineReadyCheck() } } -bool Group::_addMember(const uint64 &guid, const char* name) -{ - // get first not-full group - uint8 groupid = 0; - if (m_subGroupsCounts) - { - bool groupFound = false; - for (; groupid < MAX_RAID_SUBGROUPS; ++groupid) - { - if (m_subGroupsCounts[groupid] < MAXGROUPSIZE) - { - groupFound = true; - break; - } - } - // We are raid group and no one slot is free - if (!groupFound) - return false; - } - - return _addMember(guid, name, groupid); -} - -bool Group::_addMember(const uint64 &guid, const char* name, uint8 group) -{ - if (IsFull()) - return false; - - if (!guid) - return false; - - Player *player = sObjectMgr->GetPlayer(guid); - - MemberSlot member; - member.guid = guid; - member.name = name; - member.group = group; - member.flags = 0; - member.roles = 0; - m_memberSlots.push_back(member); - - SubGroupCounterIncrease(group); - - if (player) - { - player->SetGroupInvite(NULL); - if (player->GetGroup() && isBGGroup()) //if player is in group and he is being added to BG raid group, then call SetBattlegroundRaid() - player->SetBattlegroundRaid(this, group); - else if (player->GetGroup()) //if player is in bg raid and we are adding him to normal group, then call SetOriginalGroup() - player->SetOriginalGroup(this, group); - else //if player is not in group, then call set group - player->SetGroup(this, group); - - // if the same group invites the player back, cancel the homebind timer - InstanceGroupBind *bind = GetBoundInstance(player); - if (bind && bind->save->GetInstanceId() == player->GetInstanceId()) - player->m_InstanceValid = true; - } - - if (!isRaidGroup()) // reset targetIcons for non-raid-groups - { - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) - m_targetIcons[i] = 0; - } - - // insert into the table if we're not a battleground group - if (!isBGGroup()) - CharacterDatabase.PExecute("INSERT INTO group_member (guid, memberGuid, memberFlags, subgroup, roles) VALUES(%u, %u, %u, %u, %u)", GUID_LOPART(m_guid), GUID_LOPART(member.guid), member.flags, member.group, member.roles); - - return true; -} - -bool Group::_removeMember(const uint64 &guid) -{ - Player *player = sObjectMgr->GetPlayer(guid); - if (player) - { - //if we are removing player from battleground raid - if (isBGGroup()) - player->RemoveFromBattlegroundRaid(); - else - { - //we can remove player who is in battleground from his original group - if (player->GetOriginalGroup() == this) - player->SetOriginalGroup(NULL); - else - player->SetGroup(NULL); - } - } - - _removeRolls(guid); - - member_witerator slot = _getMemberWSlot(guid); - if (slot != m_memberSlots.end()) - { - SubGroupCounterDecrease(slot->group); - m_memberSlots.erase(slot); - } - - if (!isBGGroup()) - CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid=%u", GUID_LOPART(guid)); - - if (m_leaderGuid == guid) // leader was removed - { - if (GetMembersCount() > 0) - _setLeader(m_memberSlots.front().guid); - return true; - } - - return false; -} - -void Group::_setLeader(const uint64 &guid) -{ - member_witerator slot = _getMemberWSlot(guid); - if (slot == m_memberSlots.end()) - return; - - sScriptMgr->OnGroupChangeLeader(this, m_leaderGuid, guid); - - if (!isBGGroup()) - { - // TODO: set a time limit to have this function run rarely cause it can be slow - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - - // update the group's bound instances when changing leaders - // remove all permanent binds from the group - // in the DB also remove solo binds that will be replaced with permbinds - // from the new leader - trans->PAppend( - "DELETE FROM group_instance WHERE guid=%u AND (permanent = 1 OR " - "instance IN (SELECT instance FROM character_instance WHERE guid = '%u')" - ")", GUID_LOPART(m_guid), GUID_LOPART(slot->guid) - ); - - Player *player = sObjectMgr->GetPlayer(slot->guid); - if (player) - { - for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) - { - for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end();) - { - if (itr->second.perm) - { - itr->second.save->RemoveGroup(this); - m_boundInstances[i].erase(itr++); - } - else - ++itr; - } - } - } - - // copy the permanent binds from the new leader to the group - // overwriting the solo binds with permanent ones if necessary - // in the DB those have been deleted already - Player::ConvertInstancesToGroup(player, this, slot->guid); - - // update the group leader - trans->PAppend("UPDATE groups SET leaderGuid='%u' WHERE guid='%u'", GUID_LOPART(slot->guid), GUID_LOPART(m_guid)); - CharacterDatabase.CommitTransaction(trans); - } - - m_leaderGuid = slot->guid; - m_leaderName = slot->name; - ToggleGroupMemberFlag(slot, MEMBER_FLAG_ASSISTANT, false); -} - -void Group::_removeRolls(const uint64 &guid) -{ - for (Rolls::iterator it = RollId.begin(); it != RollId.end(); ++it) - { - Roll* roll = *it; - Roll::PlayerVote::iterator itr2 = roll->playerVote.find(guid); - if (itr2 == roll->playerVote.end()) - continue; - - if (itr2->second == GREED || itr2->second == DISENCHANT) - --roll->totalGreed; - else if (itr2->second == NEED) - --roll->totalNeed; - else if (itr2->second == PASS) - --roll->totalPass; - - if (itr2->second != NOT_VALID) - --roll->totalPlayersRolling; - - roll->playerVote.erase(itr2); - - CountRollVote(guid, roll->itemGUID, GetMembersCount()-1, MAX_ROLL_TYPE); - } -} - bool Group::_setMembersGroup(const uint64 &guid, const uint8 &group) { member_witerator slot = _getMemberWSlot(guid); @@ -1412,50 +1348,6 @@ bool Group::_setMembersGroup(const uint64 &guid, const uint8 &group) return true; } -bool Group::_setAssistantFlag(const uint64 &guid, const bool &apply) -{ - member_witerator slot = _getMemberWSlot(guid); - if (slot == m_memberSlots.end()) - return false; - - ToggleGroupMemberFlag(slot, MEMBER_FLAG_ASSISTANT, apply); - - if (!isBGGroup()) - CharacterDatabase.PExecute("UPDATE group_member SET memberFlags='%u' WHERE memberGuid='%u'", slot->flags, GUID_LOPART(guid)); - - return true; -} - -bool Group::_setMainTank(const uint64 &guid, const bool &apply) -{ - member_witerator slot = _getMemberWSlot(guid); // First check member slots to see if the target exists - if (slot == m_memberSlots.end()) - return false; - - RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINTANK); // Remove main tank flag from current if any. - ToggleGroupMemberFlag(slot, MEMBER_FLAG_MAINTANK, apply); // And apply main tank flag on new main tank. - - if (!isBGGroup()) - CharacterDatabase.PExecute("UPDATE group_member SET memberFlags='%u' WHERE memberGuid='%u'", slot->flags, GUID_LOPART(guid)); - - return true; -} - -bool Group::_setMainAssistant(const uint64 &guid, const bool &apply) -{ - member_witerator slot = _getMemberWSlot(guid); - if (slot == m_memberSlots.end()) - return false; - - RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINASSIST); // Remove main assist flag from current if any. - ToggleGroupMemberFlag(slot, MEMBER_FLAG_MAINASSIST, apply); // Apply main assist flag on new main assist. - - if (!isBGGroup()) - CharacterDatabase.PExecute("UPDATE group_member SET memberFlags='%u' WHERE memberGuid='%u'", slot->flags, GUID_LOPART(guid)); - - return true; -} - bool Group::SameSubGroup(Player const* member1, Player const* member2) const { if (!member1 || !member2) @@ -1466,55 +1358,53 @@ bool Group::SameSubGroup(Player const* member1, Player const* member2) const return member1->GetSubGroup() == member2->GetSubGroup(); } -// allows setting subgroup for offline members +// Allows setting sub groups both for online or offline members void Group::ChangeMembersGroup(const uint64 &guid, const uint8 &group) { + // Only raid groups have sub groups if (!isRaidGroup()) return; - Player *player = sObjectMgr->GetPlayer(guid); - - if (!player) - { - uint8 prevSubGroup = GetMemberGroup(guid); - if (prevSubGroup == group) - return; - - if (_setMembersGroup(guid, group)) - { - SubGroupCounterDecrease(prevSubGroup); - SendUpdate(); - } - } - else - // This methods handles itself groupcounter decrease - ChangeMembersGroup(player, group); -} - -// only for online members -void Group::ChangeMembersGroup(Player *player, const uint8 &group) -{ - if (!player || !isRaidGroup()) + // Check if player is really in the raid + member_witerator slot = _getMemberWSlot(guid); + if (slot == m_memberSlots.end()) return; - uint8 prevSubGroup = player->GetSubGroup(); + // Abort if the player is already in the target sub group + uint8 prevSubGroup = GetMemberGroup(guid); if (prevSubGroup == group) return; - if (_setMembersGroup(player->GetGUID(), group)) + // Update the player slot with the new sub group setting + slot->group = group; + + // Increase the counter of the new sub group.. + SubGroupCounterIncrease(group); + + // ..and decrease the counter of the previous one + SubGroupCounterDecrease(prevSubGroup); + + // Preserve new sub group in database for non-raid groups + if (!isBGGroup()) + CharacterDatabase.PExecute("UPDATE group_member SET subgroup='%u' WHERE memberGuid='%u'", group, GUID_LOPART(guid)); + + Player *player = sObjectMgr->GetPlayer(guid); + + // In case the moved player is online, update the player object with the new sub group references + if (player) { if (player->GetGroup() == this) player->GetGroupRef().setSubGroup(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 + // 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); } - - SubGroupCounterDecrease(prevSubGroup); - SendUpdate(); } + + // Broadcast the changes to the group + SendUpdate(); } // Retrieve the next Round-Roubin player for the group @@ -2068,31 +1958,40 @@ void Group::SetBattlegroundGroup(Battleground *bg) m_bgGroup = bg; } -void Group::SetAssistant(uint64 guid, const bool &apply) + +void Group::SetGroupMemberFlag(uint64 guid, const bool &apply, GroupMemberFlags flag) { + // Assistants, main assistants and main tanks are only available in raid groups if (!isRaidGroup()) return; - if (_setAssistantFlag(guid, apply)) - SendUpdate(); -} - -void Group::SetMainTank(uint64 guid, const bool &apply) -{ - if (!isRaidGroup()) + // Check if player is really in the raid + member_witerator slot = _getMemberWSlot(guid); + if (slot == m_memberSlots.end()) return; - if (_setMainTank(guid, apply)) - SendUpdate(); -} + // Do flag specific actions, e.g ensure uniqueness + switch (flag) { + case MEMBER_FLAG_MAINASSIST: + RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINASSIST); // Remove main assist flag from current if any. + break; + case MEMBER_FLAG_MAINTANK: + RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINTANK); // Remove main tank flag from current if any. + break; + case MEMBER_FLAG_ASSISTANT: + break; + default: + return; // This should never happen + } -void Group::SetMainAssistant(uint64 guid, const bool &apply) -{ - if (!isRaidGroup()) - return; + // Switch the actual flag + ToggleGroupMemberFlag(slot, flag, apply); - if (_setMainAssistant(guid, apply)) - SendUpdate(); + // Preserve the new setting in the db + CharacterDatabase.PExecute("UPDATE group_member SET memberFlags='%u' WHERE memberGuid='%u'", slot->flags, GUID_LOPART(guid)); + + // Broadcast the changes to the group + SendUpdate(); } Difficulty Group::GetDifficulty(bool isRaid) const diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index d7fb7c7530d..e4c4066572a 100755 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -73,6 +73,12 @@ enum GroupMemberFlags MEMBER_FLAG_MAINASSIST = 0x04, }; +enum GroupMemberAssignment +{ + GROUP_ASSIGN_MAINTANK = 0, + GROUP_ASSIGN_MAINASSIST = 1, +}; + enum GroupType { GROUPTYPE_NORMAL = 0x00, @@ -176,14 +182,14 @@ class Group ~Group(); // group manipulation methods - bool Create(const uint64 &guid, const char * name); + bool Create(Player *leader); bool LoadGroupFromDB(const uint32 &guid, QueryResult result, bool loadMembers = true); bool LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup, uint8 roles); bool AddInvite(Player *player); void RemoveInvite(Player *player); void RemoveAllInvites(); bool AddLeaderInvite(Player *player); - bool AddMember(const uint64 &guid, const char* name); + bool AddMember(Player *player); uint32 RemoveMember(const uint64 &guid, const RemoveMethod &method = GROUP_REMOVEMETHOD_DEFAULT, uint64 kicker = 0, const char* reason = NULL); void ChangeLeader(const uint64 &guid); void SetLootMethod(LootMethod method); @@ -235,10 +241,9 @@ class Group void ChangeMembersGroup(const uint64 &guid, const uint8 &group); void ChangeMembersGroup(Player *player, const uint8 &group); - void SetAssistant(uint64 guid, const bool &apply); - void SetMainTank(uint64 guid, const bool &apply); - void SetMainAssistant(uint64 guid, const bool &apply); void SetTargetIcon(uint8 id, uint64 whoGuid, uint64 targetGuid); + void SetGroupMemberFlag(uint64 guid, const bool &apply, GroupMemberFlags flag); + void RemoveUniqueGroupMemberFlag(GroupMemberFlags flag); Difficulty GetDifficulty(bool isRaid) const; Difficulty GetDungeonDifficulty() const; @@ -294,18 +299,7 @@ class Group void BroadcastGroupUpdate(void); protected: - bool _addMember(const uint64 &guid, const char* name); - bool _addMember(const uint64 &guid, const char* name, uint8 group); - bool _removeMember(const uint64 &guid); // returns true if leader has changed - void _setLeader(const uint64 &guid); - - void _removeRolls(const uint64 &guid); - bool _setMembersGroup(const uint64 &guid, const uint8 &group); - bool _setAssistantFlag(const uint64 &guid, const bool &apply); - bool _setMainTank(const uint64 &guid, const bool &apply); - bool _setMainAssistant(const uint64 &guid, const bool &apply); - void _homebindIfInstance(Player *player); void _initRaidSubGroupsCounter(); @@ -313,7 +307,6 @@ class Group member_witerator _getMemberWSlot(uint64 Guid); void SubGroupCounterIncrease(uint8 subgroup); void SubGroupCounterDecrease(uint8 subgroup); - void RemoveUniqueGroupMemberFlag(GroupMemberFlags flag); void ToggleGroupMemberFlag(member_witerator slot, uint8 flag, bool apply); MemberSlotList m_memberSlots; diff --git a/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp b/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp index d23a937e365..73eca2b947b 100755 --- a/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp @@ -57,6 +57,8 @@ void WorldSession::SendPartyResult(PartyOperation operation, const std::string& void WorldSession::HandleGroupInviteOpcode(WorldPacket & recv_data) { + sLog->outDebug("WORLD: Received CMSG_GROUP_INVITE"); + std::string membername; recv_data >> membername; recv_data.read_skip<uint32>(); @@ -191,9 +193,16 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket & recv_data) void WorldSession::HandleGroupAcceptOpcode(WorldPacket& recv_data) { + sLog->outDebug("WORLD: Received CMSG_GROUP_ACCEPT"); + recv_data.read_skip<uint32>(); Group *group = GetPlayer()->GetGroupInvite(); - if (!group) return; + + if (!group) + return; + + // Remove player from invitees in any case + group->RemoveInvite(GetPlayer()); if (group->GetLeaderGUID() == GetPlayer()->GetGUID()) { @@ -201,13 +210,7 @@ void WorldSession::HandleGroupAcceptOpcode(WorldPacket& recv_data) return; } - // remove in from ivites in any case - group->RemoveInvite(GetPlayer()); - - /** error handling **/ - /********************/ - - // not have place + // Group is full if (group->IsFull()) { SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); @@ -216,17 +219,25 @@ void WorldSession::HandleGroupAcceptOpcode(WorldPacket& recv_data) Player* leader = sObjectMgr->GetPlayer(group->GetLeaderGUID()); - // forming a new group, create it + // Forming a new group, create it if (!group->IsCreated()) { - if (leader) - group->RemoveInvite(leader); - group->Create(group->GetLeaderGUID(), group->GetLeaderName()); + // This can happen if the leader is zoning. To be removed once delayed actions for zoning are implemented + if (!leader) + { + group->RemoveAllInvites(); + return; + } + + // If we're about to create a group there really should be a leader present + ASSERT(leader); + group->RemoveInvite(leader); + group->Create(leader); sObjectMgr->AddGroup(group); } - // everything's fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!! - if (!group->AddMember(GetPlayer()->GetGUID(), GetPlayer()->GetName())) + // Everything is fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!! + if (!group->AddMember(GetPlayer())) return; group->BroadcastGroupUpdate(); @@ -234,6 +245,8 @@ void WorldSession::HandleGroupAcceptOpcode(WorldPacket& recv_data) void WorldSession::HandleGroupDeclineOpcode(WorldPacket & /*recv_data*/) { + sLog->outDebug("WORLD: Received CMSG_GROUP_DECLINE"); + Group *group = GetPlayer()->GetGroupInvite(); if (!group) return; @@ -255,6 +268,8 @@ void WorldSession::HandleGroupDeclineOpcode(WorldPacket & /*recv_data*/) void WorldSession::HandleGroupUninviteGuidOpcode(WorldPacket & recv_data) { + sLog->outDebug("WORLD: Received CMSG_GROUP_UNINVITE_GUID"); + uint64 guid; std::string reason; recv_data >> guid; @@ -301,6 +316,8 @@ void WorldSession::HandleGroupUninviteGuidOpcode(WorldPacket & recv_data) void WorldSession::HandleGroupUninviteOpcode(WorldPacket & recv_data) { + sLog->outDebug("WORLD: Received CMSG_GROUP_UNINVITE"); + std::string membername; recv_data >> membername; @@ -343,6 +360,8 @@ void WorldSession::HandleGroupUninviteOpcode(WorldPacket & recv_data) void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket & recv_data) { + sLog->outDebug("WORLD: Received CMSG_GROUP_SET_LEADER"); + Group *group = GetPlayer()->GetGroup(); if (!group) return; @@ -357,12 +376,16 @@ void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket & recv_data) return; /********************/ - // everything's fine, do it + // Everything's fine, do it group->ChangeLeader(guid); + + group->SendUpdate(); } void WorldSession::HandleGroupDisbandOpcode(WorldPacket & /*recv_data*/) { + sLog->outDebug("WORLD: Received CMSG_GROUP_DISBAND"); + Group *grp = GetPlayer()->GetGroup(); if (!grp) return; @@ -384,6 +407,8 @@ void WorldSession::HandleGroupDisbandOpcode(WorldPacket & /*recv_data*/) void WorldSession::HandleLootMethodOpcode(WorldPacket & recv_data) { + sLog->outDebug("WORLD: Received CMSG_LOOT_METHOD"); + Group *group = GetPlayer()->GetGroup(); if (!group) return; @@ -439,6 +464,8 @@ void WorldSession::HandleLootRoll(WorldPacket &recv_data) void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data) { + sLog->outDebug("WORLD: Received MSG_MINIMAP_PING"); + if (!GetPlayer()->GetGroup()) return; @@ -461,6 +488,8 @@ void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data) void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data) { + sLog->outDebug("WORLD: Received MSG_RANDOM_ROLL"); + uint32 minimum, maximum, roll; recv_data >> minimum; recv_data >> maximum; @@ -488,6 +517,8 @@ void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data) void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket & recv_data) { + sLog->outDebug("WORLD: Received MSG_RAID_TARGET_UPDATE"); + Group *group = GetPlayer()->GetGroup(); if (!group) return; @@ -516,6 +547,8 @@ void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket & recv_data) void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket & /*recv_data*/) { + sLog->outDebug("WORLD: Received CMSG_GROUP_RAID_CONVERT"); + Group *group = GetPlayer()->GetGroup(); if (!group) return; @@ -535,6 +568,8 @@ void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket & /*recv_data*/) void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket & recv_data) { + sLog->outDebug("WORLD: Received CMSG_GROUP_CHANGE_SUB_GROUP"); + // we will get correct pointer for group here, so we don't have to check if group is BG raid Group *group = GetPlayer()->GetGroup(); if (!group) @@ -548,78 +583,87 @@ void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket & recv_data) if (groupNr >= MAX_RAID_SUBGROUPS) return; - /** error handling **/ uint64 senderGuid = GetPlayer()->GetGUID(); if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) return; if (!group->HasFreeSlotSubGroup(groupNr)) return; - /********************/ Player *movedPlayer = sObjectMgr->GetPlayer(name.c_str()); + uint64 guid; if (movedPlayer) { - //Do not allow leader to change group of player in combat - if (movedPlayer->isInCombat()) - return; - - // everything's fine, do it - group->ChangeMembersGroup(movedPlayer, groupNr); + guid = movedPlayer->GetGUID(); } else - group->ChangeMembersGroup(sObjectMgr->GetPlayerGUIDByName(name.c_str()), groupNr); + { + CharacterDatabase.escape_string(name); + guid = sObjectMgr->GetPlayerGUIDByName(name.c_str()); + } + + group->ChangeMembersGroup(guid, groupNr); } void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket & recv_data) { + sLog->outDebug("WORLD: Received CMSG_GROUP_ASSISTANT_LEADER"); + Group *group = GetPlayer()->GetGroup(); if (!group) return; + if (!group->IsLeader(GetPlayer()->GetGUID())) + return; + uint64 guid; - uint8 flag; + bool apply; recv_data >> guid; - recv_data >> flag; + recv_data >> apply; - /** error handling **/ - if (!group->IsLeader(GetPlayer()->GetGUID())) - return; - /********************/ + group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_ASSISTANT); - // everything's fine, do it - group->SetAssistant(guid, (flag != 0)); + group->SendUpdate(); } void WorldSession::HandlePartyAssignmentOpcode(WorldPacket & recv_data) { - sLog->outDebug("MSG_PARTY_ASSIGNMENT"); + sLog->outDebug("WORLD: Received MSG_PARTY_ASSIGNMENT"); Group *group = GetPlayer()->GetGroup(); if (!group) return; - uint8 flag, apply; - uint64 guid; - recv_data >> flag >> apply; - recv_data >> guid; - - /** error handling **/ uint64 senderGuid = GetPlayer()->GetGUID(); if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) return; - /********************/ - // everything's fine, do it - if (flag == 0) - group->SetMainTank(guid, apply); + uint8 assignment; + bool apply; + uint64 guid; + recv_data >> assignment >> apply; + recv_data >> guid; + + switch (assignment) + { + case GROUP_ASSIGN_MAINASSIST: + group->RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINASSIST); + group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_MAINASSIST); + break; + case GROUP_ASSIGN_MAINTANK: + group->RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINTANK); // Remove main assist flag from current if any. + group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_MAINTANK); + default: + break; + } - else if (flag == 1) - group->SetMainAssistant(guid, apply); + group->SendUpdate(); } void WorldSession::HandleRaidReadyCheckOpcode(WorldPacket & recv_data) { + sLog->outDebug("WORLD: Received MSG_RAID_READY_CHECK"); + Group *group = GetPlayer()->GetGroup(); if (!group) return; |
