feat(Core/Visibility): Visibility improvements part 1 (#22624)
This commit is contained in:
@@ -412,6 +412,9 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
|
||||
m_isInstantFlightOn = true;
|
||||
|
||||
_wasOutdoor = true;
|
||||
|
||||
GetObjectVisibilityContainer().InitForPlayer();
|
||||
|
||||
sScriptMgr->OnConstructPlayer(this);
|
||||
}
|
||||
|
||||
@@ -5707,20 +5710,7 @@ void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool s
|
||||
SendDirectMessage(data);
|
||||
|
||||
Acore::MessageDistDeliverer notifier(this, data, dist);
|
||||
Cell::VisitWorldObjects(this, notifier, dist);
|
||||
}
|
||||
|
||||
void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin, bool ownTeamOnly, bool required3dDist) const
|
||||
{
|
||||
if (self)
|
||||
SendDirectMessage(data);
|
||||
|
||||
dist += GetObjectSize();
|
||||
if (includeMargin)
|
||||
dist += VISIBILITY_COMPENSATION; // pussywizard: to ensure everyone receives all important packets
|
||||
|
||||
Acore::MessageDistDeliverer notifier(this, data, dist, ownTeamOnly, nullptr, required3dDist);
|
||||
Cell::VisitWorldObjects(this, notifier, dist);
|
||||
notifier.Visit(GetObjectVisibilityContainer().GetVisiblePlayersMap());
|
||||
}
|
||||
|
||||
void Player::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const
|
||||
@@ -5728,8 +5718,8 @@ void Player::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcv
|
||||
if (skipped_rcvr != this)
|
||||
SendDirectMessage(data);
|
||||
|
||||
Acore::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr);
|
||||
Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
|
||||
Acore::MessageDistDeliverer notifier(this, data, 0.0f, false, skipped_rcvr);
|
||||
notifier.Visit(GetObjectVisibilityContainer().GetVisiblePlayersMap());
|
||||
}
|
||||
|
||||
void Player::SendDirectMessage(WorldPacket const* data) const
|
||||
@@ -7711,23 +7701,26 @@ bool Player::CheckAmmoCompatibility(ItemTemplate const* ammo_proto) const
|
||||
|
||||
void Player::SendQuestGiverStatusMultiple()
|
||||
{
|
||||
if (GetObjectVisibilityContainer().GetVisibleWorldObjectsMap()->empty())
|
||||
return;
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4);
|
||||
data << uint32(count); // placeholder
|
||||
|
||||
for (GuidUnorderedSet::const_iterator itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
|
||||
DoForAllVisibleWorldObjects([this, &data, &count](WorldObject* worldObject)
|
||||
{
|
||||
uint32 questStatus = DIALOG_STATUS_NONE;
|
||||
|
||||
if ((*itr).IsAnyTypeCreature())
|
||||
if (worldObject->IsCreature())
|
||||
{
|
||||
// need also pet quests case support
|
||||
Creature* questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, *itr);
|
||||
Creature* questgiver = worldObject->ToCreature();
|
||||
if (!questgiver || questgiver->IsHostileTo(this))
|
||||
continue;
|
||||
return;
|
||||
if (!questgiver->HasNpcFlag(UNIT_NPC_FLAG_QUESTGIVER))
|
||||
continue;
|
||||
return;
|
||||
|
||||
questStatus = GetQuestDialogStatus(questgiver);
|
||||
|
||||
@@ -7735,11 +7728,11 @@ void Player::SendQuestGiverStatusMultiple()
|
||||
data << uint8(questStatus);
|
||||
++count;
|
||||
}
|
||||
else if ((*itr).IsGameObject())
|
||||
else if (worldObject->IsGameObject())
|
||||
{
|
||||
GameObject* questgiver = GetMap()->GetGameObject(*itr);
|
||||
GameObject* questgiver = worldObject->ToGameObject();
|
||||
if (!questgiver || questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER)
|
||||
continue;
|
||||
return;
|
||||
|
||||
questStatus = GetQuestDialogStatus(questgiver);
|
||||
|
||||
@@ -7747,7 +7740,7 @@ void Player::SendQuestGiverStatusMultiple()
|
||||
data << uint8(questStatus);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
data.put<uint32>(0, count); // write real count
|
||||
GetSession()->SendPacket(&data);
|
||||
@@ -9383,7 +9376,12 @@ void Player::Say(std::string_view text, Language language, WorldObject const* /*
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_SAY, language, this, this, _text);
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true, false, false, true);
|
||||
|
||||
SendDirectMessage(&data);
|
||||
|
||||
// Special handling for messages, do not use visibility map for stealthed units
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), false, nullptr, true);
|
||||
Cell::VisitWorldObjects(this, notifier, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY));
|
||||
}
|
||||
|
||||
void Player::Say(uint32 textId, WorldObject const* target /*= nullptr*/)
|
||||
@@ -9404,7 +9402,12 @@ void Player::Yell(std::string_view text, Language language, WorldObject const* /
|
||||
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_YELL, language, this, this, _text);
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), true, false, false, true);
|
||||
|
||||
SendDirectMessage(&data);
|
||||
|
||||
// Special handling for messages, do not use visibility map for stealthed units
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), false, nullptr, true);
|
||||
Cell::VisitWorldObjects(this, notifier, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL));
|
||||
}
|
||||
|
||||
void Player::Yell(uint32 textId, WorldObject const* target /*= nullptr*/)
|
||||
@@ -9426,7 +9429,11 @@ void Player::TextEmote(std::string_view text, WorldObject const* /*= nullptr*/,
|
||||
WorldPacket data;
|
||||
ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text);
|
||||
|
||||
SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, false, !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_EMOTE), true);
|
||||
SendDirectMessage(&data);
|
||||
|
||||
// Special handling for messages, do not use visibility map for stealthed units
|
||||
Acore::MessageDistDeliverer notifier(this, &data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_EMOTE), nullptr, true);
|
||||
Cell::VisitWorldObjects(this, notifier, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
|
||||
}
|
||||
|
||||
void Player::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, bool /*isBossEmote = false*/)
|
||||
@@ -10487,35 +10494,24 @@ void Player::ContinueTaxiFlight()
|
||||
|
||||
void Player::SendTaxiNodeStatusMultiple()
|
||||
{
|
||||
for (auto itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
|
||||
DoForAllVisibleWorldObjects([this](WorldObject* worldObject)
|
||||
{
|
||||
if (!itr->IsCreature())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Creature* creature = ObjectAccessor::GetCreature(*this, *itr);
|
||||
Creature* creature = worldObject->ToCreature();
|
||||
if (!creature || creature->IsHostileTo(this))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
|
||||
if (!creature->HasNpcFlag(UNIT_NPC_FLAG_FLIGHTMASTER))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
|
||||
uint32 nearestNode = sObjectMgr->GetNearestTaxiNode(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetMapId(), GetTeamId());
|
||||
if (!nearestNode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
|
||||
WorldPacket data(SMSG_TAXINODE_STATUS, 9);
|
||||
data << *itr;
|
||||
data << creature->GetGUID();
|
||||
data << uint8(m_taxi.IsTaximaskNodeKnown(nearestNode) ? 1 : 0);
|
||||
SendDirectMessage(&data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Player::ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs)
|
||||
@@ -11393,31 +11389,22 @@ WorldLocation Player::GetStartPosition() const
|
||||
|
||||
bool Player::HaveAtClient(WorldObject const* u) const
|
||||
{
|
||||
if (u == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Motion Transports are always present in player's client
|
||||
if (GameObject const* gameobject = u->ToGameObject())
|
||||
{
|
||||
if (gameobject->IsMotionTransport())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return m_clientGUIDs.find(u->GetGUID()) != m_clientGUIDs.end();
|
||||
return HaveAtClient(u->GetGUID());
|
||||
}
|
||||
|
||||
bool Player::HaveAtClient(ObjectGuid guid) const
|
||||
{
|
||||
if (guid == GetGUID())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_clientGUIDs.find(guid) != m_clientGUIDs.end();
|
||||
return GetObjectVisibilityContainer().GetVisibleWorldObjectsMap()->find(guid) != GetObjectVisibilityContainer().GetVisibleWorldObjectsMap()->end();
|
||||
}
|
||||
|
||||
bool Player::IsNeverVisible() const
|
||||
|
||||
@@ -2043,7 +2043,6 @@ public:
|
||||
|
||||
void SendMessageToSet(WorldPacket const* data, bool self) const override;
|
||||
void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self) const override;
|
||||
void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin, bool ownTeamOnly, bool required3dDist = false) const;
|
||||
void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const override;
|
||||
void SendTeleportAckPacket();
|
||||
|
||||
@@ -2397,7 +2396,6 @@ public:
|
||||
void SetEntryPoint();
|
||||
|
||||
// currently visible objects at player client
|
||||
GuidUnorderedSet m_clientGUIDs;
|
||||
std::vector<Unit*> m_newVisible; // pussywizard
|
||||
|
||||
[[nodiscard]] bool HaveAtClient(WorldObject const* u) const;
|
||||
|
||||
@@ -1635,35 +1635,35 @@ void Player::UpdateObjectVisibility(bool forced, bool fromUpdate)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target,
|
||||
inline void UpdateVisibilityOf_helper(Player* player, T* target,
|
||||
std::vector<Unit*>& /*v*/)
|
||||
{
|
||||
s64.insert(target->GetGUID());
|
||||
player->GetObjectVisibilityContainer().LinkWorldObjectVisibility(target);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target,
|
||||
inline void UpdateVisibilityOf_helper(Player* player, GameObject* target,
|
||||
std::vector<Unit*>& /*v*/)
|
||||
{
|
||||
// @HACK: This is to prevent objects like deeprun tram from disappearing
|
||||
// when player moves far from its spawn point while riding it
|
||||
if ((target->GetGOInfo()->type != GAMEOBJECT_TYPE_TRANSPORT))
|
||||
s64.insert(target->GetGUID());
|
||||
player->GetObjectVisibilityContainer().LinkWorldObjectVisibility(target);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Creature* target,
|
||||
inline void UpdateVisibilityOf_helper(Player* player, Creature* target,
|
||||
std::vector<Unit*>& v)
|
||||
{
|
||||
s64.insert(target->GetGUID());
|
||||
player->GetObjectVisibilityContainer().LinkWorldObjectVisibility(target);
|
||||
v.push_back(target);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Player* target,
|
||||
inline void UpdateVisibilityOf_helper(Player* player, Player* target,
|
||||
std::vector<Unit*>& v)
|
||||
{
|
||||
s64.insert(target->GetGUID());
|
||||
player->GetObjectVisibilityContainer().LinkWorldObjectVisibility(target);
|
||||
v.push_back(target);
|
||||
}
|
||||
|
||||
@@ -1692,7 +1692,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data,
|
||||
BeforeVisibilityDestroy<T>(target, this);
|
||||
|
||||
target->BuildOutOfRangeUpdateBlock(&data);
|
||||
m_clientGUIDs.erase(target->GetGUID());
|
||||
GetObjectVisibilityContainer().UnlinkWorldObjectVisibility(target);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1700,7 +1700,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data,
|
||||
if (CanSeeOrDetect(target, false, true))
|
||||
{
|
||||
target->BuildCreateUpdateBlockForPlayer(&data, this);
|
||||
UpdateVisibilityOf_helper(m_clientGUIDs, target, visibleNow);
|
||||
UpdateVisibilityOf_helper(this, target, visibleNow);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1726,7 +1726,7 @@ void Player::UpdateVisibilityOf(WorldObject* target)
|
||||
BeforeVisibilityDestroy<Creature>(target->ToCreature(), this);
|
||||
|
||||
target->DestroyForPlayer(this);
|
||||
m_clientGUIDs.erase(target->GetGUID());
|
||||
GetObjectVisibilityContainer().UnlinkWorldObjectVisibility(target);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1734,7 +1734,7 @@ void Player::UpdateVisibilityOf(WorldObject* target)
|
||||
if (CanSeeOrDetect(target, false, true))
|
||||
{
|
||||
target->SendUpdateToPlayer(this);
|
||||
m_clientGUIDs.insert(target->GetGUID());
|
||||
GetObjectVisibilityContainer().LinkWorldObjectVisibility(target);
|
||||
|
||||
// target aura duration for caster show only if target exist at
|
||||
// caster client send data at target visibility change (adding to
|
||||
@@ -1747,69 +1747,67 @@ void Player::UpdateVisibilityOf(WorldObject* target)
|
||||
|
||||
void Player::UpdateTriggerVisibility()
|
||||
{
|
||||
if (m_clientGUIDs.empty())
|
||||
return;
|
||||
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
UpdateData udata;
|
||||
WorldPacket packet;
|
||||
for (GuidUnorderedSet::iterator itr = m_clientGUIDs.begin();
|
||||
itr != m_clientGUIDs.end(); ++itr)
|
||||
if (GetObjectVisibilityContainer().GetVisibleWorldObjectsMap()->empty())
|
||||
return;
|
||||
|
||||
UpdateData udata;
|
||||
DoForAllVisibleWorldObjects([this, &udata](WorldObject* worldObject)
|
||||
{
|
||||
if ((*itr).IsCreatureOrVehicle())
|
||||
if (worldObject->IsCreature())
|
||||
{
|
||||
Creature* creature = GetMap()->GetCreature(*itr);
|
||||
Creature* creature = worldObject->ToCreature();
|
||||
// Update fields of triggers, transformed units or unselectable
|
||||
// units (values dependent on GM state)
|
||||
if (!creature || (!creature->IsTrigger() &&
|
||||
!creature->HasTransformAura() &&
|
||||
!creature->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)))
|
||||
continue;
|
||||
!creature->HasTransformAura() &&
|
||||
!creature->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)))
|
||||
return;
|
||||
|
||||
creature->SetFieldNotifyFlag(UF_FLAG_PUBLIC);
|
||||
creature->BuildValuesUpdateBlockForPlayer(&udata, this);
|
||||
creature->RemoveFieldNotifyFlag(UF_FLAG_PUBLIC);
|
||||
}
|
||||
else if ((*itr).IsGameObject())
|
||||
else if (worldObject->IsGameObject())
|
||||
{
|
||||
GameObject* go = GetMap()->GetGameObject(*itr);
|
||||
GameObject* go = worldObject->ToGameObject();
|
||||
if (!go)
|
||||
continue;
|
||||
return;
|
||||
|
||||
go->SetFieldNotifyFlag(UF_FLAG_PUBLIC);
|
||||
go->BuildValuesUpdateBlockForPlayer(&udata, this);
|
||||
go->RemoveFieldNotifyFlag(UF_FLAG_PUBLIC);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!udata.HasData())
|
||||
return;
|
||||
|
||||
WorldPacket packet;
|
||||
udata.BuildPacket(packet);
|
||||
GetSession()->SendPacket(&packet);
|
||||
}
|
||||
|
||||
void Player::UpdateForQuestWorldObjects()
|
||||
{
|
||||
if (m_clientGUIDs.empty())
|
||||
if (GetObjectVisibilityContainer().GetVisibleWorldObjectsMap()->empty())
|
||||
return;
|
||||
|
||||
UpdateData udata;
|
||||
WorldPacket packet;
|
||||
for (GuidUnorderedSet::iterator itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
|
||||
UpdateData udata;
|
||||
DoForAllVisibleWorldObjects([this, &udata](WorldObject* worldObject)
|
||||
{
|
||||
if ((*itr).IsGameObject())
|
||||
if (worldObject->IsGameObject())
|
||||
{
|
||||
if (GameObject* obj = ObjectAccessor::GetGameObject(*this, *itr))
|
||||
if (GameObject* obj = worldObject->ToGameObject())
|
||||
obj->BuildValuesUpdateBlockForPlayer(&udata, this);
|
||||
}
|
||||
else if ((*itr).IsCreatureOrVehicle())
|
||||
else if (worldObject->IsCreature())
|
||||
{
|
||||
Creature* obj = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, *itr);
|
||||
Creature* obj = worldObject->ToCreature();
|
||||
if (!obj)
|
||||
continue;
|
||||
return;
|
||||
|
||||
// check if this unit requires quest specific flags
|
||||
if (obj->HasNpcFlag(UNIT_NPC_FLAG_SPELLCLICK))
|
||||
@@ -1833,12 +1831,14 @@ void Player::UpdateForQuestWorldObjects()
|
||||
}
|
||||
}
|
||||
else if (obj->HasNpcFlag(UNIT_NPC_FLAG_VENDOR_MASK | UNIT_NPC_FLAG_TRAINER))
|
||||
{
|
||||
obj->BuildValuesUpdateBlockForPlayer(&udata, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!udata.HasData())
|
||||
return;
|
||||
|
||||
WorldPacket packet;
|
||||
udata.BuildPacket(packet);
|
||||
GetSession()->SendPacket(&packet);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user