diff options
author | Shauren <shauren.trinity@gmail.com> | 2025-07-31 16:20:51 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2025-07-31 16:20:51 +0200 |
commit | 223be4c4eb937cc3a68c09c93d81faf930155adf (patch) | |
tree | b6da0f6b1dcfdbddb15b9ec9fb5e475441c31633 | |
parent | 2c9b67f00be95bd816dbaa9db43838a67e187753 (diff) |
Core/Objects: Broadcast object destroy packets to players using Far Sight and Mind Vision
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 142 |
1 files changed, 71 insertions, 71 deletions
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 9da68100476..eaea679d01a 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -3739,28 +3739,82 @@ void WorldObject::PlayObjectSound(int32 soundKitId, ObjectGuid targetObjectGUID, SendMessageToSet(pkt.Write(), true); } -void WorldObject::DestroyForNearbyPlayers() +template <std::invocable<Player*> Work> +struct WorldObjectVisibleChangeVisitor { - if (!IsInWorld()) - return; + Work& work; + + explicit WorldObjectVisibleChangeVisitor(Work& work_) : work(work_) { } + + void Visit(PlayerMapType& m) const + { + for (GridReference<Player>& ref : m) + { + Player* source = ref.GetSource(); + + work(source); + + for (Player* viewer : source->GetSharedVisionList()) + work(viewer); + } + } + + void Visit(CreatureMapType& m) const + { + for (GridReference<Creature>& ref : m) + for (Player* viewer : ref.GetSource()->GetSharedVisionList()) + work(viewer); + } + + void Visit(DynamicObjectMapType& m) const + { + for (GridReference<DynamicObject>& ref : m) + { + DynamicObject* source = ref.GetSource(); + ObjectGuid guid = source->GetCasterGUID(); - auto destroyer = [this](Player* player) + if (guid.IsPlayer()) + { + //GetCaster() will be nullptr if DynObj is in removelist + if (Player* caster = ObjectAccessor::GetPlayer(*source, guid)) + if (*caster->m_activePlayerData->FarsightObject == source->GetGUID()) + work(caster); + } + } + } + + template <class SKIP> + static void Visit(GridRefManager<SKIP> const&) { } +}; + +struct WorldObjectClientDestroyWork +{ + WorldObject* object; + + void operator()(Player* player) const { - if (player == this) + if (player == object) return; - if (!player->HaveAtClient(this)) + if (!player->HaveAtClient(object)) return; - if (Unit const* unit = ToUnit(); unit && unit->GetCharmerGUID() == player->GetGUID()) /// @todo this is for puppet + if (Unit const* unit = object->ToUnit(); unit && unit->GetCharmerGUID() == player->GetGUID()) /// @todo this is for puppet return; - DestroyForPlayer(player); - player->m_clientGUIDs.erase(GetGUID()); - }; + object->DestroyForPlayer(player); + player->m_clientGUIDs.erase(object->GetGUID()); + } +}; - Trinity::PlayerDistWorker worker(this, GetVisibilityRange(), destroyer); - Cell::VisitWorldObjects(this, worker, GetVisibilityRange()); +void WorldObject::DestroyForNearbyPlayers() +{ + if (!IsInWorld()) + return; + + WorldObjectClientDestroyWork destroyer{ .object = this }; + WorldObjectVisibleChangeVisitor visitor(destroyer); + Cell::VisitWorldObjects(this, visitor, GetVisibilityRange()); } void WorldObject::UpdateObjectVisibility(bool /*forced*/) @@ -3775,77 +3829,23 @@ struct WorldObjectChangeAccumulator { UpdateDataMapType& i_updateDatas; WorldObject& i_object; - GuidSet plr_list; + GuidUnorderedSet plr_list; WorldObjectChangeAccumulator(WorldObject &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) { } - void Visit(PlayerMapType &m) - { - Player* source = nullptr; - for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - source = iter->GetSource(); - BuildPacket(source); - - if (!source->GetSharedVisionList().empty()) - { - SharedVisionList::const_iterator it = source->GetSharedVisionList().begin(); - for (; it != source->GetSharedVisionList().end(); ++it) - BuildPacket(*it); - } - } - } - - void Visit(CreatureMapType &m) - { - Creature* source = nullptr; - for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - source = iter->GetSource(); - if (!source->GetSharedVisionList().empty()) - { - SharedVisionList::const_iterator it = source->GetSharedVisionList().begin(); - for (; it != source->GetSharedVisionList().end(); ++it) - BuildPacket(*it); - } - } - } - - void Visit(DynamicObjectMapType &m) - { - DynamicObject* source = nullptr; - for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - source = iter->GetSource(); - ObjectGuid guid = source->GetCasterGUID(); - - if (guid.IsPlayer()) - { - //Caster may be nullptr if DynObj is in removelist - if (Player* caster = ObjectAccessor::FindPlayer(guid)) - if (*caster->m_activePlayerData->FarsightObject == source->GetGUID()) - BuildPacket(caster); - } - } - } - - void BuildPacket(Player* player) + void operator()(Player* player) { // Only send update once to a player - if (plr_list.find(player->GetGUID()) == plr_list.end() && player->HaveAtClient(&i_object)) - { + if (player->HaveAtClient(&i_object) && plr_list.insert(player->GetGUID()).second) i_object.BuildFieldsUpdate(player, i_updateDatas); - plr_list.insert(player->GetGUID()); - } } - - template<class SKIP> void Visit(GridRefManager<SKIP> &) { } }; void WorldObject::BuildUpdate(UpdateDataMapType& data_map) { WorldObjectChangeAccumulator notifier(*this, data_map); + WorldObjectVisibleChangeVisitor visitor(notifier); //we must build packets for all visible players - Cell::VisitWorldObjects(this, notifier, GetVisibilityRange()); + Cell::VisitWorldObjects(this, visitor, GetVisibilityRange()); ClearUpdateMask(false); } |