diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index a0aceeb32e1..7f103f14f32 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1155,7 +1155,7 @@ bool Object::PrintIndexError(uint32 index, bool set) const WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0), m_name(""), m_isActive(false), m_isFarVisible(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr), m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_outdoors(true), m_liquidStatus(LIQUID_MAP_NO_WATER), -m_currMap(nullptr), m_InstanceId(0), _dbPhase(0), m_notifyflags(0), +m_wmoGroupID(0), m_currMap(nullptr), m_InstanceId(0), _dbPhase(0), m_notifyflags(0), m_aiAnimKitId(0), m_movementAnimKitId(0), m_meleeAnimKitId(0) { m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST); @@ -1261,6 +1261,7 @@ void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& da m_outdoors = data.outdoors; m_staticFloorZ = data.floorZ; m_liquidStatus = data.liquidStatus; + m_wmoGroupID = data.areaInfo.is_initialized() ? data.areaInfo->groupId : 0; } void WorldObject::AddToWorld() diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 05a97a71092..51b638f2a16 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -324,6 +324,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const { zoneid = m_zoneId, areaid = m_areaId; } bool IsOutdoors() const { return m_outdoors; } ZLiquidStatus GetLiquidStatus() const { return m_liquidStatus; } + uint32 GetWMOGroupId() const { return m_wmoGroupID; } InstanceScript* GetInstanceScript() const; @@ -502,6 +503,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation float m_staticFloorZ; bool m_outdoors; ZLiquidStatus m_liquidStatus; + uint32 m_wmoGroupID; //these functions are used mostly for Relocate() and Corpse/Player specific stuff... //use them ONLY in LoadFromDB()/Create() funcs and nowhere else! diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 5d6fc148a01..53b376cf0c1 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -5875,6 +5875,8 @@ ActionButton const* Player::GetActionButton(uint8 button) bool Player::UpdatePosition(float x, float y, float z, float orientation, bool teleport) { + uint32 oldWmoGroupId = GetWMOGroupId(); + if (!Unit::UpdatePosition(x, y, z, orientation, teleport)) return false; @@ -5893,10 +5895,17 @@ bool Player::UpdatePosition(float x, float y, float z, float orientation, bool t m_needsZoneUpdate = false; } - // group update + // Add group update flags if (GetGroup()) + { + // Position has changed SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION); + // Player is no longer on a WMO that belongs to the same area + if (oldWmoGroupId != GetWMOGroupId()) + SetGroupUpdateFlag(GROUP_UPDATE_FLAG_WMO_GROUP_ID); + } + CheckAreaExploreAndOutdoor(); // Update mount capabilities diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 863eefb8d13..144e84b8c77 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -12435,6 +12435,10 @@ void Unit::OnPhaseChange() { if (!IsInWorld()) return; + + // Inform player groups that a member's phase has changed so the next PartyMemberState packet will update the phasing accordingly + if (IsPlayer() && ToPlayer()->GetGroup()) + ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PHASE); } void Unit::UpdateObjectVisibility(bool forced) diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 1f25dfd8611..ce123a6270e 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -34,6 +34,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" +#include "PartyPackets.h" #include "PhasingHandler.h" #include "Player.h" #include "Random.h" @@ -1812,15 +1813,15 @@ void Group::UpdatePlayerOutOfRange(Player* player) if (!player || !player->IsInWorld()) return; - WorldPacket data; - player->GetSession()->BuildPartyMemberStatsChangedPacket(player, &data); + WorldPackets::Party::PartyMemberState packet; + packet.Initialize(player); Player* member; for (GroupReference* itr = GetFirstMember(); itr != nullptr; itr = itr->next()) { member = itr->GetSource(); if (member && member != player && (!member->IsInMap(player) || !member->IsWithinDist(player, member->GetSightRange(), false))) - member->SendDirectMessage(&data); + member->SendDirectMessage(packet.Write()); } } diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 27a01315db8..d1f8cc36ed3 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -105,7 +105,7 @@ enum GroupUpdateFlags 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_WMO_GROUP_ID = 0x00000100, // int16 (WMOGroupID) 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) @@ -135,7 +135,7 @@ enum GroupUpdateFlags 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_UNK100 |GROUP_UPDATE_FLAG_POSITION | + GROUP_UPDATE_FLAG_LEVEL | GROUP_UPDATE_FLAG_ZONE | GROUP_UPDATE_FLAG_WMO_GROUP_ID |GROUP_UPDATE_FLAG_POSITION | GROUP_UPDATE_FLAG_AURAS | GROUP_UPDATE_FLAG_PHASE | GROUP_UPDATE_FLAG_UNK400000 | GROUP_UPDATE_FLAG_UNK800000 | GROUP_UPDATE_FLAG_UNK1000000 | GROUP_UPDATE_FLAG_UNK2000000 | GROUP_UPDATE_FLAG_UNK4000000 | GROUP_UPDATE_FLAG_UNK8000000 | GROUP_UPDATE_FLAG_UNK10000000 | GROUP_UPDATE_FLAG_UNK20000000 | GROUP_UPDATE_FLAG_UNK40000000 diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index f4fc08a3f5b..19297ff4a3f 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -24,6 +24,7 @@ #include "Log.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" +#include "PartyPackets.h" #include "Pet.h" #include "PhasingHandler.h" #include "Player.h" @@ -982,237 +983,6 @@ void WorldSession::HandleRaidReadyCheckFinishedOpcode(WorldPacket& /*recvData*/) // Is any reaction need? } -void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data) -{ - uint32 mask = player->GetGroupUpdateFlag(); - - if (mask == GROUP_UPDATE_FLAG_NONE) - return; - - if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also - mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); - - if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets - mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER); - - data->Initialize(SMSG_PARTY_MEMBER_STATS, 80); // average value - *data << player->GetPackGUID(); - *data << uint32(mask); - - if (mask & GROUP_UPDATE_FLAG_STATUS) - { - uint16 playerStatus = MEMBER_STATUS_ONLINE; - if (player->IsPvP()) - playerStatus |= MEMBER_STATUS_PVP; - - if (!player->IsAlive()) - { - if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - playerStatus |= MEMBER_STATUS_GHOST; - else - playerStatus |= MEMBER_STATUS_DEAD; - } - - if (player->IsFFAPvP()) - playerStatus |= MEMBER_STATUS_PVP_FFA; - - if (player->isAFK()) - playerStatus |= MEMBER_STATUS_AFK; - - if (player->isDND()) - playerStatus |= MEMBER_STATUS_DND; - - *data << uint16(playerStatus); - } - - if (mask & GROUP_UPDATE_FLAG_CUR_HP) - *data << int32(player->GetHealth()); - - if (mask & GROUP_UPDATE_FLAG_MAX_HP) - *data << int32(player->GetMaxHealth()); - - Powers powerType = player->GetPowerType(); - if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) - *data << uint8(powerType); - - if (mask & GROUP_UPDATE_FLAG_CUR_POWER) - *data << int16(player->GetPower(powerType)); - - if (mask & GROUP_UPDATE_FLAG_MAX_POWER) - *data << int16(player->GetMaxPower(powerType)); - - if (mask & GROUP_UPDATE_FLAG_LEVEL) - *data << int16(player->getLevel()); - - if (mask & GROUP_UPDATE_FLAG_ZONE) - *data << int16(player->GetZoneId()); - - if (mask & GROUP_UPDATE_FLAG_UNK100) - *data << uint16(0); - - if (mask & GROUP_UPDATE_FLAG_POSITION) - { - *data << uint16(player->GetPositionX()); - *data << uint16(player->GetPositionY()); - *data << uint16(player->GetPositionZ()); - } - - if (mask & GROUP_UPDATE_FLAG_AURAS) - { - *data << uint8(0); - uint64 auramask = player->GetAuraUpdateMaskForRaid(); - *data << uint64(auramask); - *data << uint32(MAX_AURAS); // count - for (uint32 i = 0; i < MAX_AURAS; ++i) - { - if (auramask & (uint64(1) << i)) - { - AuraApplication const* aurApp = player->GetVisibleAura(i); - if (!aurApp) - { - *data << uint32(0); - *data << uint16(0); - continue; - } - - *data << uint32(aurApp->GetBase()->GetId()); - *data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) - { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) - *data << int32(eff->GetAmount()); - else - *data << int32(0); - } - } - } - } - } - - Pet* pet = player->GetPet(); - if (mask & GROUP_UPDATE_FLAG_PET_GUID) - { - if (pet) - *data << uint64(pet->GetGUID()); - else - *data << uint64(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_NAME) - { - if (pet) - *data << pet->GetName(); - else - *data << uint8(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID) - { - if (pet) - *data << int16(pet->GetDisplayId()); - else - *data << uint16(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP) - { - if (pet) - *data << int32(pet->GetHealth()); - else - *data << int32(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP) - { - if (pet) - *data << int32(pet->GetMaxHealth()); - else - *data << int32(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) - { - if (pet) - *data << uint8(pet->GetPowerType()); - else - *data << uint8(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER) - { - if (pet) - *data << int16(pet->GetPower(pet->GetPowerType())); - else - *data << int16(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER) - { - if (pet) - *data << int16(pet->GetMaxPower(pet->GetPowerType())); - else - *data << int16(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_AURAS) - { - if (pet) - { - *data << uint8(0); - uint64 auramask = pet->GetAuraUpdateMaskForRaid(); - *data << uint64(auramask); - *data << uint32(MAX_AURAS); // count - for (uint32 i = 0; i < MAX_AURAS; ++i) - { - if (auramask & (uint64(1) << i)) - { - AuraApplication const* aurApp = pet->GetVisibleAura(i); - if (!aurApp) - { - *data << uint32(0); - *data << uint16(0); - continue; - } - - *data << uint32(aurApp->GetBase()->GetId()); - *data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) - { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) - *data << int32(eff->GetAmount()); - else - *data << int32(0); - } - } - } - } - } - else - { - *data << uint8(0); - *data << uint64(0); - *data << uint32(0); - } - } - - if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT) - { - if (Vehicle* veh = player->GetVehicle()) - *data << int32(veh->GetVehicleInfo()->SeatID[player->m_movementInfo.transport.seat]); - else - *data << int32(0); - } - - if (mask & GROUP_UPDATE_FLAG_PHASE) - PhasingHandler::FillPartyMemberPhase(data, player->GetPhaseShift()); -} - /*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData) { @@ -1223,168 +993,17 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData) Player* player = ObjectAccessor::FindConnectedPlayer(Guid); if (!player) { - WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2); - data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data << Guid.WriteAsPacked(); - data << uint32(GROUP_UPDATE_FLAG_STATUS); - data << uint16(MEMBER_STATUS_OFFLINE); - SendPacket(&data); + WorldPackets::Party::PartyMemberState packet(true); + packet.MemberGuid = Guid; + packet.ChangeMask = GROUP_UPDATE_FLAG_STATUS; + packet.MemberStats.Status = MEMBER_STATUS_OFFLINE; + SendPacket(packet.Write()); return; } - Pet* pet = player->GetPet(); - Powers powerType = player->GetPowerType(); - - WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8); - data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data << player->GetPackGUID(); - - uint32 updateFlags = GROUP_UPDATE_FLAG_STATUS | 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_ZONE | GROUP_UPDATE_FLAG_POSITION | GROUP_UPDATE_FLAG_AURAS - | GROUP_UPDATE_FLAG_PET_NAME | GROUP_UPDATE_FLAG_PET_MODEL_ID | GROUP_UPDATE_FLAG_PET_AURAS; - - if (powerType != POWER_MANA) - updateFlags |= GROUP_UPDATE_FLAG_POWER_TYPE; - - if (pet) - updateFlags |= GROUP_UPDATE_FLAG_PET_GUID | 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; - - if (player->GetVehicle()) - updateFlags |= GROUP_UPDATE_FLAG_VEHICLE_SEAT; - - if (!player->GetPhaseShift().GetPhases().empty()) - updateFlags |= GROUP_UPDATE_FLAG_PHASE; - - uint16 playerStatus = MEMBER_STATUS_ONLINE; - if (player->IsPvP()) - playerStatus |= MEMBER_STATUS_PVP; - - if (!player->IsAlive()) - { - if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - playerStatus |= MEMBER_STATUS_GHOST; - else - playerStatus |= MEMBER_STATUS_DEAD; - } - - if (player->IsFFAPvP()) - playerStatus |= MEMBER_STATUS_PVP_FFA; - - if (player->isAFK()) - playerStatus |= MEMBER_STATUS_AFK; - - if (player->isDND()) - playerStatus |= MEMBER_STATUS_DND; - - data << uint32(updateFlags); - data << uint16(playerStatus); // GROUP_UPDATE_FLAG_STATUS - data << uint32(player->GetHealth()); // GROUP_UPDATE_FLAG_CUR_HP - data << uint32(player->GetMaxHealth()); // GROUP_UPDATE_FLAG_MAX_HP - if (updateFlags & GROUP_UPDATE_FLAG_POWER_TYPE) - data << uint8(powerType); - - data << uint16(player->GetPower(powerType)); // GROUP_UPDATE_FLAG_CUR_POWER - data << uint16(player->GetMaxPower(powerType)); // GROUP_UPDATE_FLAG_MAX_POWER - data << uint16(player->getLevel()); // GROUP_UPDATE_FLAG_LEVEL - data << uint16(player->GetZoneId()); // GROUP_UPDATE_FLAG_ZONE - data << uint16(player->GetPositionX()); // GROUP_UPDATE_FLAG_POSITION - data << uint16(player->GetPositionY()); // GROUP_UPDATE_FLAG_POSITION - data << uint16(player->GetPositionZ()); // GROUP_UPDATE_FLAG_POSITION - - // GROUP_UPDATE_FLAG_AURAS - data << uint8(1); - uint64 auramask = 0; - size_t maskPos = data.wpos(); - data << uint64(auramask); // placeholder - data << uint32(MAX_AURAS); // count - - for (uint8 i = 0; i < MAX_AURAS; ++i) - { - if (AuraApplication const* aurApp = player->GetVisibleAura(i)) - { - auramask |= (uint64(1) << i); - - data << uint32(aurApp->GetBase()->GetId()); - data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) - { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) - data << int32(eff->GetAmount()); - else - data << int32(0); - } - } - } - } - - data.put(maskPos, auramask); // GROUP_UPDATE_FLAG_AURAS - - if (updateFlags & GROUP_UPDATE_FLAG_PET_GUID) - data << uint64(ASSERT_NOTNULL(pet)->GetGUID()); - - data << std::string(pet ? pet->GetName() : ""); // GROUP_UPDATE_FLAG_PET_NAME - data << uint16(pet ? pet->GetDisplayId() : 0); // GROUP_UPDATE_FLAG_PET_MODEL_ID - - if (updateFlags & GROUP_UPDATE_FLAG_PET_CUR_HP) - data << uint32(pet->GetHealth()); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_MAX_HP) - data << uint32(pet->GetMaxHealth()); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_POWER_TYPE) - data << (uint8)pet->GetPowerType(); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_CUR_POWER) - data << uint16(pet->GetPower(pet->GetPowerType())); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_MAX_POWER) - data << uint16(pet->GetMaxPower(pet->GetPowerType())); - - // GROUP_UPDATE_FLAG_PET_AURAS - uint64 petAuraMask = 0; - data << uint8(1); - maskPos = data.wpos(); - data << uint64(petAuraMask); // placeholder - data << uint32(MAX_AURAS); // count - if (pet) - { - for (uint8 i = 0; i < MAX_AURAS; ++i) - { - if (AuraApplication const* aurApp = pet->GetVisibleAura(i)) - { - petAuraMask |= (uint64(1) << i); - - data << uint32(aurApp->GetBase()->GetId()); - data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) - { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) - data << int32(eff->GetAmount()); - else - data << int32(0); - } - } - } - } - } - - data.put(maskPos, petAuraMask); // GROUP_UPDATE_FLAG_PET_AURAS - - if (updateFlags & GROUP_UPDATE_FLAG_VEHICLE_SEAT) - data << uint32(player->GetVehicle()->GetVehicleInfo()->SeatID[player->m_movementInfo.transport.seat]); - - if (updateFlags & GROUP_UPDATE_FLAG_PHASE) - PhasingHandler::FillPartyMemberPhase(&data, player->GetPhaseShift()); - - SendPacket(&data); + WorldPackets::Party::PartyMemberState packet(true); + packet.Initialize(player); + SendPacket(packet.Write()); } void WorldSession::HandleRequestRaidInfoOpcode(WorldPacket& /*recvData*/) diff --git a/src/server/game/Phasing/PhasingHandler.cpp b/src/server/game/Phasing/PhasingHandler.cpp index ee07f0507e2..9299d31220c 100644 --- a/src/server/game/Phasing/PhasingHandler.cpp +++ b/src/server/game/Phasing/PhasingHandler.cpp @@ -24,6 +24,7 @@ #include "Map.h" #include "MiscPackets.h" #include "ObjectMgr.h" +#include "PartyPackets.h" #include "PhaseShift.h" #include "Player.h" #include "SpellAuraEffects.h" @@ -416,12 +417,12 @@ void PhasingHandler::SendToPlayer(Player const* player) SendToPlayer(player, player->GetPhaseShift()); } -void PhasingHandler::FillPartyMemberPhase(WorldPacket* data, PhaseShift const& phaseShift) +void PhasingHandler::FillPartyMemberPhase(WorldPackets::Party::PartyMemberPhaseStates* partyMemberPhases, PhaseShift const& phaseShift) { - *data << int32(phaseShift.Flags.AsUnderlyingType()); - *data << int32(phaseShift.Phases.size()); - for (auto itr = phaseShift.Phases.begin(); itr != phaseShift.Phases.end(); ++itr) - *data << int16(itr->Id); + partyMemberPhases->PhaseShiftFlags = phaseShift.Flags.AsUnderlyingType(); + partyMemberPhases->List.reserve(phaseShift.Phases.size()); + std::transform(phaseShift.Phases.begin(), phaseShift.Phases.end(), std::back_inserter(partyMemberPhases->List), + [](PhaseShift::PhaseRef const& phase) -> uint16 { return phase.Id; }); } PhaseShift const& PhasingHandler::GetEmptyPhaseShift() diff --git a/src/server/game/Phasing/PhasingHandler.h b/src/server/game/Phasing/PhasingHandler.h index 7cbb17183fd..29b3fbaaff9 100644 --- a/src/server/game/Phasing/PhasingHandler.h +++ b/src/server/game/Phasing/PhasingHandler.h @@ -27,6 +27,13 @@ class PhaseShift; class Player; class WorldObject; class WorldPacket; +namespace WorldPackets +{ + namespace Party + { + struct PartyMemberPhaseStates; + } +} class TC_GAME_API PhasingHandler { @@ -48,7 +55,7 @@ public: static void SendToPlayer(Player const* player, PhaseShift const& phaseShift); static void SendToPlayer(Player const* player); - static void FillPartyMemberPhase(WorldPacket* data, PhaseShift const& phaseShift); + static void FillPartyMemberPhase(WorldPackets::Party::PartyMemberPhaseStates* partyMemberPhases, PhaseShift const& phaseShift); static PhaseShift const& GetEmptyPhaseShift(); static void InitDbPhaseShift(PhaseShift& phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId); diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h index bb093333a4c..4e3ae0d85b3 100644 --- a/src/server/game/Server/Packets/AllPackets.h +++ b/src/server/game/Server/Packets/AllPackets.h @@ -29,6 +29,7 @@ #include "MiscPackets.h" #include "MovementPackets.h" #include "NPCPackets.h" +#include "PartyPackets.h" #include "QuestPackets.h" #include "QueryPackets.h" #include "SystemPackets.h" diff --git a/src/server/game/Server/Packets/PartyPackets.cpp b/src/server/game/Server/Packets/PartyPackets.cpp new file mode 100644 index 00000000000..8c1fac41317 --- /dev/null +++ b/src/server/game/Server/Packets/PartyPackets.cpp @@ -0,0 +1,308 @@ +/* + * 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 . + */ + +#include "PartyPackets.h" +#include "Group.h" +#include "Pet.h" +#include "Player.h" +#include "PhasingHandler.h" +#include "SpellAuras.h" +#include "SpellAuraEffects.h" +#include "Vehicle.h" + +void WorldPackets::Party::PartyMemberState::Initialize(Player const* player) +{ + MemberGuid = player->GetGUID(); + + // Update Flags + if (GetOpcode() == SMSG_PARTY_MEMBER_FULL_STATE) + { + ChangeMask = GROUP_UPDATE_FLAG_STATUS | 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_ZONE | GROUP_UPDATE_FLAG_WMO_GROUP_ID | GROUP_UPDATE_FLAG_POSITION | GROUP_UPDATE_FLAG_AURAS + | GROUP_UPDATE_FLAG_PET_AURAS | GROUP_UPDATE_FLAG_PHASE | GROUP_UPDATE_FLAG_UNK400000 | GROUP_UPDATE_FLAG_UNK800000 + | GROUP_UPDATE_FLAG_UNK1000000 | GROUP_UPDATE_FLAG_UNK2000000 | GROUP_UPDATE_FLAG_UNK4000000 | GROUP_UPDATE_FLAG_UNK8000000 + | GROUP_UPDATE_FLAG_UNK10000000 | GROUP_UPDATE_FLAG_UNK20000000 | GROUP_UPDATE_FLAG_UNK40000000; + + // Additional update flags depending on the player's state + if (player->GetPowerType() != POWER_MANA) + ChangeMask |= GROUP_UPDATE_FLAG_POWER_TYPE; + + if (player->GetPet()) + ChangeMask |= 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; + + if (player->GetVehicle()) + ChangeMask |= GROUP_UPDATE_FLAG_VEHICLE_SEAT; + } + else + { + ChangeMask = player->GetGroupUpdateFlag(); + + // Additional update flags based on the current group update flags + if (ChangeMask & GROUP_UPDATE_FLAG_POWER_TYPE) + ChangeMask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); + + if (ChangeMask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) + ChangeMask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER); + } + + // Status + MemberStats.Status = MEMBER_STATUS_ONLINE; + + if (player->IsPvP()) + MemberStats.Status |= MEMBER_STATUS_PVP; + + if (!player->IsAlive()) + { + if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + MemberStats.Status |= MEMBER_STATUS_GHOST; + else + MemberStats.Status |= MEMBER_STATUS_DEAD; + } + + if (player->IsFFAPvP()) + MemberStats.Status |= MEMBER_STATUS_PVP_FFA; + + if (player->isAFK()) + MemberStats.Status |= MEMBER_STATUS_AFK; + + if (player->isDND()) + MemberStats.Status |= MEMBER_STATUS_DND; + + // Level + MemberStats.Level = player->getLevel(); + + // Health + MemberStats.CurrentHealth = player->GetHealth(); + MemberStats.MaxHealth = player->GetMaxHealth(); + + // Power + MemberStats.PowerType = player->GetPowerType(); + MemberStats.CurrentPower = player->GetPower(player->GetPowerType()); + MemberStats.MaxPower = player->GetMaxPower(player->GetPowerType()); + + // Position + MemberStats.ZoneID = player->GetZoneId(); + MemberStats.PositionX = int16(player->GetPositionX()); + MemberStats.PositionY = int16(player->GetPositionY()); + MemberStats.PositionZ = int16(player->GetPositionZ()); + MemberStats.WmoGroupID = uint16(player->GetWMOGroupId()); + + // Vehicle + if (player->GetVehicle() && player->GetVehicle()->GetVehicleInfo()) + MemberStats.VehicleSeat = player->GetVehicle()->GetVehicleInfo()->SeatID[player->m_movementInfo.transport.seat]; + + // Auras + MemberStats.AuraMask = player->GetAuraUpdateMaskForRaid(); + for (uint8 i = 0; i < MAX_AURAS; ++i) + { + if (!(MemberStats.AuraMask & (uint64(1) << i))) + continue; + + if (AuraApplication const* aurApp = player->GetVisibleAura(i)) + { + WorldPackets::Party::PartyMemberAuraStates aura; + aura.SpellID = aurApp->GetBase()->GetId(); + aura.Flags = aurApp->GetFlags(); + + if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) + { + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (AuraEffect const* aurEff = aurApp->GetBase()->GetEffect(i)) + aura.Points.push_back(aurEff->GetAmount()); + else + aura.Points.push_back(0); + } + } + + MemberStats.Auras.push_back(aura); + } + } + + // Phases + PhasingHandler::FillPartyMemberPhase(&MemberStats.Phases, player->GetPhaseShift()); + + + // Pet + if (player->GetPet()) + { + ::Pet* pet = player->GetPet(); + + MemberStats.PetStats = boost::in_place(); + + MemberStats.PetStats->GUID = pet->GetGUID(); + MemberStats.PetStats->Name = pet->GetName(); + MemberStats.PetStats->ModelId = pet->GetDisplayId(); + + MemberStats.PetStats->CurrentHealth = pet->GetHealth(); + MemberStats.PetStats->MaxHealth = pet->GetMaxHealth(); + MemberStats.PetStats->PowerType = pet->GetPowerType(); + MemberStats.PetStats->CurrentPower = player->GetPower(player->GetPowerType()); + MemberStats.PetStats->MaxPower = player->GetMaxPower(player->GetPowerType()); + + // Auras + MemberStats.PetStats->AuraMask = player->GetAuraUpdateMaskForRaid(); + for (uint8 i = 0; i < MAX_AURAS; ++i) + { + if (!(MemberStats.PetStats->AuraMask & (uint64(1) << i))) + continue; + + if (AuraApplication const* aurApp = pet->GetVisibleAura(i)) + { + WorldPackets::Party::PartyMemberAuraStates aura; + aura.SpellID = aurApp->GetBase()->GetId(); + aura.Flags = aurApp->GetFlags(); + + if (aurApp->GetFlags() & AFLAG_ANY_EFFECT_AMOUNT_SENT) + { + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (AuraEffect const* aurEff = aurApp->GetBase()->GetEffect(i)) + aura.Points.push_back(aurEff->GetAmount()); + else + aura.Points.push_back(0); + } + } + + MemberStats.PetStats->Auras.push_back(aura); + } + } + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::PartyMemberPhaseStates const& phases) +{ + data << uint32(phases.PhaseShiftFlags); + data << uint32(phases.List.size()); + + for (uint16 phaseId : phases.List) + data << uint16(phaseId); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::PartyMemberAuraStates const& aura) +{ + data << uint32(aura.SpellID); + data << uint16(aura.Flags); + for (int32 points : aura.Points) + data << int32(points); + + return data; +} + +WorldPacket const* WorldPackets::Party::PartyMemberState::Write() +{ + if (_worldPacket.GetOpcode() == SMSG_PARTY_MEMBER_FULL_STATE) + _worldPacket << uint8(ForEnemy); + + _worldPacket << MemberGuid.WriteAsPacked(); + _worldPacket << uint32(ChangeMask); + + if (ChangeMask & GROUP_UPDATE_FLAG_STATUS) + _worldPacket << uint16(MemberStats.Status); + + if (ChangeMask & GROUP_UPDATE_FLAG_CUR_HP) + _worldPacket << int32(MemberStats.CurrentHealth); + + if (ChangeMask & GROUP_UPDATE_FLAG_MAX_HP) + _worldPacket << int32(MemberStats.MaxHealth); + + if (ChangeMask & GROUP_UPDATE_FLAG_POWER_TYPE) + _worldPacket << uint8(MemberStats.PowerType); + + if (ChangeMask & GROUP_UPDATE_FLAG_CUR_POWER) + _worldPacket << uint16(MemberStats.CurrentPower); + + if (ChangeMask & GROUP_UPDATE_FLAG_MAX_POWER) + _worldPacket << uint16(MemberStats.MaxPower); + + if (ChangeMask & GROUP_UPDATE_FLAG_LEVEL) + _worldPacket << uint16(MemberStats.Level); + + if (ChangeMask & GROUP_UPDATE_FLAG_ZONE) + _worldPacket << uint16(MemberStats.ZoneID); + + if (ChangeMask & GROUP_UPDATE_FLAG_WMO_GROUP_ID) + _worldPacket << int16(MemberStats.WmoGroupID); + + if (ChangeMask & GROUP_UPDATE_FLAG_POSITION) + { + _worldPacket << int16(MemberStats.PositionX); + _worldPacket << int16(MemberStats.PositionY); + _worldPacket << int16(MemberStats.PositionZ); + } + + if (ChangeMask & GROUP_UPDATE_FLAG_AURAS) + { + _worldPacket << uint8(_worldPacket.GetOpcode() == SMSG_PARTY_MEMBER_FULL_STATE); + _worldPacket << uint64(MemberStats.AuraMask); + _worldPacket << uint32(MemberStats.Auras.size()); + for (WorldPackets::Party::PartyMemberAuraStates const& aura : MemberStats.Auras) + _worldPacket << aura; + } + + if (MemberStats.PetStats.is_initialized()) + { + if (ChangeMask & GROUP_UPDATE_FLAG_PET_GUID) + _worldPacket << MemberStats.PetStats->GUID; + + if (ChangeMask & GROUP_UPDATE_FLAG_PET_NAME) + _worldPacket << MemberStats.PetStats->Name; + + if (ChangeMask & GROUP_UPDATE_FLAG_PET_MODEL_ID) + _worldPacket << int16(MemberStats.PetStats->ModelId); + + if (ChangeMask & GROUP_UPDATE_FLAG_PET_CUR_HP) + _worldPacket << int32(MemberStats.PetStats->CurrentHealth); + + if (ChangeMask & GROUP_UPDATE_FLAG_PET_MAX_HP) + _worldPacket << int32(MemberStats.PetStats->MaxHealth); + + if (ChangeMask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) + _worldPacket << uint8(MemberStats.PetStats->PowerType); + + if (ChangeMask & GROUP_UPDATE_FLAG_PET_CUR_POWER) + _worldPacket << uint16(MemberStats.PetStats->CurrentPower); + + if (ChangeMask & GROUP_UPDATE_FLAG_PET_MAX_POWER) + _worldPacket << uint16(MemberStats.PetStats->MaxPower); + } + + // Pet auras may be sent even when no pet is present + if (ChangeMask & GROUP_UPDATE_FLAG_PET_AURAS) + { + _worldPacket << uint8(_worldPacket.GetOpcode() == SMSG_PARTY_MEMBER_FULL_STATE); + _worldPacket << uint64(MemberStats.PetStats.is_initialized() ? MemberStats.PetStats->AuraMask : 0); + _worldPacket << uint32(MemberStats.PetStats.is_initialized() ? MemberStats.PetStats->Auras.size() : 0); + + if (MemberStats.PetStats.is_initialized()) + for (WorldPackets::Party::PartyMemberAuraStates const& aura : MemberStats.PetStats->Auras) + _worldPacket << aura; + } + + if (ChangeMask & GROUP_UPDATE_FLAG_VEHICLE_SEAT) + _worldPacket << int32(MemberStats.VehicleSeat); + + if (ChangeMask & GROUP_UPDATE_FLAG_PHASE) + _worldPacket << MemberStats.Phases; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/PartyPackets.h b/src/server/game/Server/Packets/PartyPackets.h new file mode 100644 index 00000000000..0a66a9bdb6c --- /dev/null +++ b/src/server/game/Server/Packets/PartyPackets.h @@ -0,0 +1,92 @@ +/* + * 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 . + */ + +#ifndef PartyPackets_h__ +#define PartyPackets_h__ + +#include "Packet.h" + +namespace WorldPackets +{ + namespace Party + { + struct PartyMemberPhaseStates + { + uint32 PhaseShiftFlags = 0; + std::vector List; + }; + + struct PartyMemberAuraStates + { + int32 SpellID = 0; + uint16 Flags = 0; + std::vector Points; + }; + + struct PartyMemberPetStats + { + ObjectGuid GUID; + std::string Name; + int16 ModelId = 0; + int32 CurrentHealth = 0; + int32 MaxHealth = 0; + uint8 PowerType = 0u; + uint16 CurrentPower = 0; + uint16 MaxPower = 0; + uint64 AuraMask = 0; + std::vector Auras; + }; + + struct PartyMemberStats + { + uint16 Level = 0; + uint16 Status = 0; + int32 CurrentHealth = 0; + int32 MaxHealth = 0; + uint8 PowerType = 0u; + uint16 CurrentPower = 0; + uint16 MaxPower = 0; + uint16 ZoneID = 0; + uint16 WmoGroupID = 0; + int16 PositionX = 0; + int16 PositionY = 0; + int16 PositionZ = 0; + int32 VehicleSeat = 0; + uint64 AuraMask = 0; + + PartyMemberPhaseStates Phases; + std::vector Auras; + Optional PetStats; + }; + + class PartyMemberState final : public ServerPacket + { + public: + PartyMemberState(bool fullUpdate = false) : ServerPacket(fullUpdate ? SMSG_PARTY_MEMBER_FULL_STATE : SMSG_PARTY_MEMBER_STATE, 80) { } + + WorldPacket const* Write() override; + void Initialize(Player const* player); + + bool ForEnemy = false; + ObjectGuid MemberGuid; + uint32 ChangeMask = 0; + PartyMemberStats MemberStats; + }; + } +} + +#endif // PartyPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index f2f70beda91..6be0de280c8 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1084,8 +1084,8 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_PAGE_TEXT_QUERY_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTYKILLLOG, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_COMMAND_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATS, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATS_FULL, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_FULL_STATE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PAUSE_MIRROR_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PERIODICAURALOG, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETGODMODE, STATUS_NEVER, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index aebc933de38..21db11309f2 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -1040,8 +1040,8 @@ enum OpcodeServer SMSG_PAGE_TEXT_QUERY_RESPONSE = 0x2B14, SMSG_PARTYKILLLOG = 0x4937, SMSG_PARTY_COMMAND_RESULT = 0x6E07, - SMSG_PARTY_MEMBER_STATS = 0x2104, - SMSG_PARTY_MEMBER_STATS_FULL = 0x0215, + SMSG_PARTY_MEMBER_STATE = 0x2104, + SMSG_PARTY_MEMBER_FULL_STATE = 0x0215, SMSG_PAUSE_MIRROR_TIMER = 0x4015, SMSG_PERIODICAURALOG = 0x0416, SMSG_PETGODMODE = 0x2E36, diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 64e06cc7c93..fd46a8a3522 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -546,8 +546,6 @@ class TC_GAME_API WorldSession void SendNotInArenaTeamPacket(uint8 type); void SendPetitionShowList(ObjectGuid guid); - void BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data); - void DoLootRelease(ObjectGuid lguid); // Account mute time