summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTakenbacon <revoke1336@live.com>2025-09-07 04:02:03 -0700
committerGitHub <noreply@github.com>2025-09-07 08:02:03 -0300
commita28824df85040e68f35938c3e085f0f107c84ef5 (patch)
tree220177010140f8bb8710f2433da76f79e8ee5186 /src
parentd55851c513df8a337e2c77719003324cc3c51b69 (diff)
feat(Core/Visibility): Far visibility worldobjects (#22828)
Diffstat (limited to 'src')
-rw-r--r--src/common/Dynamic/TypeContainer.h46
-rw-r--r--src/common/Dynamic/TypeContainerFunctions.h96
-rw-r--r--src/common/Dynamic/TypeContainerVisitor.h21
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp4
-rw-r--r--src/server/game/Entities/Object/Object.cpp95
-rw-r--r--src/server/game/Entities/Object/Object.h27
-rw-r--r--src/server/game/Entities/Object/ObjectDefines.h1
-rw-r--r--src/server/game/Entities/Player/Player.cpp16
-rw-r--r--src/server/game/Entities/Player/Player.h1
-rw-r--r--src/server/game/Entities/Player/PlayerUpdates.cpp17
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp26
-rw-r--r--src/server/game/Grids/Cells/Cell.h2
-rw-r--r--src/server/game/Grids/Cells/CellImpl.h10
-rw-r--r--src/server/game/Grids/GridCell.h30
-rw-r--r--src/server/game/Grids/GridDefines.h8
-rw-r--r--src/server/game/Grids/MapGrid.h23
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.cpp65
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h9
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiersImpl.h12
-rw-r--r--src/server/game/Maps/Map.cpp64
-rw-r--r--src/server/game/Maps/Map.h9
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp33
22 files changed, 460 insertions, 155 deletions
diff --git a/src/common/Dynamic/TypeContainer.h b/src/common/Dynamic/TypeContainer.h
index 0c338de5da..6240eb48df 100644
--- a/src/common/Dynamic/TypeContainer.h
+++ b/src/common/Dynamic/TypeContainer.h
@@ -26,6 +26,7 @@
#include "Dynamic/TypeList.h"
#include "GridRefMgr.h"
#include <unordered_map>
+#include <vector>
/*
* @class ContainerMapList is a mulit-type container for map elements
@@ -50,6 +51,24 @@ struct ContainerMapList<TypeList<H, T>>
ContainerMapList<T> _TailElements;
};
+template<class OBJECT>
+struct ContainerVector
+{
+ std::vector<OBJECT*> _element;
+};
+
+template<>
+struct ContainerVector<TypeNull>
+{
+};
+
+template<class H, class T>
+struct ContainerVector<TypeList<H, T>>
+{
+ ContainerVector<H> _elements;
+ ContainerVector<T> _TailElements;
+};
+
template<class OBJECT, class KEY_TYPE>
struct ContainerUnorderedMap
{
@@ -123,6 +142,33 @@ private:
ContainerMapList<OBJECT_TYPES> i_elements;
};
+template<class OBJECT_TYPES>
+class TypeVectorContainer
+{
+public:
+ template<class SPECIFIC_TYPE> [[nodiscard]] std::size_t Count() const { return Acore::Count(i_elements, (SPECIFIC_TYPE*)nullptr); }
+
+ template<class SPECIFIC_TYPE>
+ bool Insert(SPECIFIC_TYPE* obj)
+ {
+ SPECIFIC_TYPE* t = Acore::Insert(i_elements, obj);
+ return (t != nullptr);
+ }
+
+ template<class SPECIFIC_TYPE>
+ bool Remove(SPECIFIC_TYPE* obj)
+ {
+ SPECIFIC_TYPE* t = Acore::Remove(i_elements, obj);
+ return (t != nullptr);
+ }
+
+ ContainerVector<OBJECT_TYPES>& GetElements() { return i_elements; }
+ [[nodiscard]] const ContainerVector<OBJECT_TYPES>& GetElements() const { return i_elements; }
+
+private:
+ ContainerVector<OBJECT_TYPES> i_elements;
+};
+
template<class OBJECT_TYPES, class KEY_TYPE>
class TypeUnorderedMapContainer
{
diff --git a/src/common/Dynamic/TypeContainerFunctions.h b/src/common/Dynamic/TypeContainerFunctions.h
index b517f4529a..61735d7d89 100644
--- a/src/common/Dynamic/TypeContainerFunctions.h
+++ b/src/common/Dynamic/TypeContainerFunctions.h
@@ -239,5 +239,101 @@ namespace Acore
// SPECIFIC_TYPE* t = Remove(elements._elements, obj);
// return ( t != nullptr ? t : Remove(elements._TailElements, obj));
//}
+
+ /* ContainerVector Helpers */
+ // count functions
+ template<class SPECIFIC_TYPE>
+ std::size_t Count(const ContainerVector<SPECIFIC_TYPE>& elements, SPECIFIC_TYPE* /*fake*/)
+ {
+ return elements._element.getSize();
+ }
+
+ template<class SPECIFIC_TYPE>
+ std::size_t Count(const ContainerVector<TypeNull>& /*elements*/, SPECIFIC_TYPE* /*fake*/)
+ {
+ return 0;
+ }
+
+ template<class SPECIFIC_TYPE, class T>
+ std::size_t Count(const ContainerVector<T>& /*elements*/, SPECIFIC_TYPE* /*fake*/)
+ {
+ return 0;
+ }
+
+ template<class SPECIFIC_TYPE, class T>
+ std::size_t Count(const ContainerVector<TypeList<SPECIFIC_TYPE, T>>& elements, SPECIFIC_TYPE* fake)
+ {
+ return Count(elements._elements, fake);
+ }
+
+ template<class SPECIFIC_TYPE, class H, class T>
+ std::size_t Count(const ContainerVector<TypeList<H, T>>& elements, SPECIFIC_TYPE* fake)
+ {
+ return Count(elements._TailElements, fake);
+ }
+
+ // non-const insert functions
+ template<class SPECIFIC_TYPE>
+ SPECIFIC_TYPE* Insert(ContainerVector<SPECIFIC_TYPE>& elements, SPECIFIC_TYPE* obj)
+ {
+ elements._element.push_back(obj);
+ return obj;
+ }
+
+ template<class SPECIFIC_TYPE>
+ SPECIFIC_TYPE* Insert(ContainerVector<TypeNull>& /*elements*/, SPECIFIC_TYPE* /*obj*/)
+ {
+ return nullptr;
+ }
+
+ // this is a missed
+ template<class SPECIFIC_TYPE, class T>
+ SPECIFIC_TYPE* Insert(ContainerVector<T>& /*elements*/, SPECIFIC_TYPE* /*obj*/)
+ {
+ return nullptr; // a missed
+ }
+
+ // Recursion
+ template<class SPECIFIC_TYPE, class H, class T>
+ SPECIFIC_TYPE* Insert(ContainerVector<TypeList<H, T>>& elements, SPECIFIC_TYPE* obj)
+ {
+ SPECIFIC_TYPE* t = Insert(elements._elements, obj);
+ return (t != nullptr ? t : Insert(elements._TailElements, obj));
+ }
+
+ // non-const remove method
+ template<class SPECIFIC_TYPE> SPECIFIC_TYPE* Remove(ContainerVector<SPECIFIC_TYPE>& elements, SPECIFIC_TYPE *obj)
+ {
+ // Simple vector find/swap/pop, this container should be very lightly used
+ // so I don't suspect the linear search complexity to be an issue
+ auto itr = std::find(elements._element.begin(), elements._element.end(), obj);
+ if (itr != elements._element.end())
+ {
+ // Swap the element to be removed with the last element
+ std::swap(*itr, elements._element.back());
+
+ // Remove the last element (which is now the element we wanted to remove)
+ elements._element.pop_back();
+ }
+ return obj;
+ }
+
+ template<class SPECIFIC_TYPE> SPECIFIC_TYPE* Remove(ContainerVector<TypeNull> &/*elements*/, SPECIFIC_TYPE * /*obj*/)
+ {
+ return nullptr;
+ }
+
+ // this is a missed
+ template<class SPECIFIC_TYPE, class T> SPECIFIC_TYPE* Remove(ContainerVector<T> &/*elements*/, SPECIFIC_TYPE * /*obj*/)
+ {
+ return nullptr; // a missed
+ }
+
+ template<class SPECIFIC_TYPE, class T, class H> SPECIFIC_TYPE* Remove(ContainerVector<TypeList<H, T> > &elements, SPECIFIC_TYPE *obj)
+ {
+ // The head element is bad
+ SPECIFIC_TYPE* t = Remove(elements._elements, obj);
+ return ( t != nullptr ? t : Remove(elements._TailElements, obj));
+ }
}
#endif
diff --git a/src/common/Dynamic/TypeContainerVisitor.h b/src/common/Dynamic/TypeContainerVisitor.h
index 1553d918af..066f6f3085 100644
--- a/src/common/Dynamic/TypeContainerVisitor.h
+++ b/src/common/Dynamic/TypeContainerVisitor.h
@@ -56,6 +56,27 @@ template<class VISITOR, class OBJECT_TYPES> void VisitorHelper(VISITOR& v, TypeM
VisitorHelper(v, c.GetElements());
}
+// VectorContainer
+template<class VISITOR> void VisitorHelper(VISITOR& /*v*/, ContainerVector<TypeNull>& /*c*/) {}
+
+template<class VISITOR, class T> void VisitorHelper(VISITOR& v, ContainerVector<T>& c)
+{
+ v.Visit(c._element);
+}
+
+// recursion container map list
+template<class VISITOR, class H, class T> void VisitorHelper(VISITOR& v, ContainerVector<TypeList<H, T>>& c)
+{
+ VisitorHelper(v, c._elements);
+ VisitorHelper(v, c._TailElements);
+}
+
+// for TypeMapContainer
+template<class VISITOR, class OBJECT_TYPES> void VisitorHelper(VISITOR& v, TypeVectorContainer<OBJECT_TYPES>& c)
+{
+ VisitorHelper(v, c.GetElements());
+}
+
// TypeUnorderedMapContainer
template<class VISITOR, class KEY_TYPE>
void VisitorHelper(VISITOR& /*v*/, ContainerUnorderedMap<TypeNull, KEY_TYPE>& /*c*/) { }
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 1fa5a4177f..f258db1caf 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -431,15 +431,11 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
// Check if GameObject is Large
if (goinfo->IsLargeGameObject())
- {
SetVisibilityDistanceOverride(VisibilityDistanceType::Large);
- }
// Check if GameObject is Infinite
if (goinfo->IsInfiniteGameObject())
- {
SetVisibilityDistanceOverride(VisibilityDistanceType::Infinite);
- }
return true;
}
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 3081013be7..2cd31a8fa8 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1037,7 +1037,7 @@ void MovementInfo::OutDebug()
}
WorldObject::WorldObject() : WorldLocation(),
- LastUsedScriptID(0), m_name(""), m_isActive(false), m_visibilityDistanceOverride(), m_zoneScript(nullptr),
+ LastUsedScriptID(0), m_name(""), m_isActive(false), _visibilityDistanceOverrideType(VisibilityDistanceType::Normal), m_zoneScript(nullptr),
_zoneId(0), _areaId(0), _floorZ(INVALID_HEIGHT), _outdoors(false), _liquidData(), _updatePositionData(false), m_transport(nullptr),
m_currMap(nullptr), _heartbeatTimer(HEARTBEAT_INTERVAL), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true),
m_notifyflags(0), m_executed_notifies(0), _objectVisibilityContainer(this)
@@ -1082,15 +1082,36 @@ void WorldObject::setActive(bool on)
map->AddObjectToPendingUpdateList(this);
}
+float WorldObject::GetVisibilityOverrideDistance() const
+{
+ ASSERT(_visibilityDistanceOverrideType < VisibilityDistanceType::Max);
+ return VisibilityDistances[AsUnderlyingType(_visibilityDistanceOverrideType)];
+}
+
void WorldObject::SetVisibilityDistanceOverride(VisibilityDistanceType type)
{
ASSERT(type < VisibilityDistanceType::Max);
+
+ if (type == GetVisibilityOverrideType())
+ return;
+
if (IsPlayer())
- {
return;
+
+ if (IsVisibilityOverridden())
+ {
+ if (IsFarVisible())
+ GetMap()->RemoveWorldObjectFromFarVisibleMap(this);
+ else if (IsZoneWideVisible())
+ GetMap()->RemoveWorldObjectFromZoneWideVisibleMap(GetZoneId(), this);
}
- m_visibilityDistanceOverride = VisibilityDistances[AsUnderlyingType(type)];
+ if (type == VisibilityDistanceType::Large || type == VisibilityDistanceType::Gigantic)
+ GetMap()->AddWorldObjectToFarVisibleMap(this);
+ else if (type == VisibilityDistanceType::Infinite)
+ GetMap()->AddWorldObjectToZoneWideVisibleMap(GetZoneId(), this);
+
+ _visibilityDistanceOverrideType = type;
}
void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
@@ -1127,6 +1148,8 @@ void WorldObject::UpdatePositionData()
void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
{
+ uint32 const oldZoneId = _zoneId;
+
_zoneId = _areaId = data.areaId;
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(_areaId))
@@ -1136,6 +1159,17 @@ void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& da
_outdoors = data.outdoors;
_floorZ = data.floorZ;
_liquidData = data.liquidInfo;
+
+ // Has zone ID changed?
+ if (oldZoneId != _zoneId)
+ {
+ // If so, check if we are far visibility overridden object and refresh maps if needed.
+ if (IsZoneWideVisible())
+ {
+ GetMap()->RemoveWorldObjectFromZoneWideVisibleMap(oldZoneId, this);
+ GetMap()->AddWorldObjectToZoneWideVisibleMap(_zoneId, this);
+ }
+ }
}
void WorldObject::AddToWorld()
@@ -1150,6 +1184,9 @@ void WorldObject::RemoveFromWorld()
if (!IsInWorld())
return;
+ if (IsZoneWideVisible())
+ GetMap()->RemoveWorldObjectFromZoneWideVisibleMap(GetZoneId(), this);
+
DestroyForVisiblePlayers();
GetObjectVisibilityContainer().CleanVisibilityReferences();
@@ -1612,26 +1649,16 @@ float WorldObject::GetGridActivationRange() const
float WorldObject::GetVisibilityRange() const
{
- if (IsVisibilityOverridden() && IsCreature())
- {
- return *m_visibilityDistanceOverride;
- }
+ if (IsCreature() && IsVisibilityOverridden())
+ return GetVisibilityOverrideDistance();
else if (IsGameObject())
{
- {
- if (IsInWintergrasp())
- {
- return VISIBILITY_DIST_WINTERGRASP + VISIBILITY_INC_FOR_GOBJECTS;
- }
- else if (IsVisibilityOverridden())
- {
- return *m_visibilityDistanceOverride;
- }
- else
- {
- return GetMap()->GetVisibilityRange() + VISIBILITY_INC_FOR_GOBJECTS;
- }
- }
+ if (IsInWintergrasp())
+ return VISIBILITY_DIST_WINTERGRASP;
+ else if (IsVisibilityOverridden())
+ return GetVisibilityOverrideDistance();
+ else
+ return GetMap()->GetVisibilityRange();
}
else
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
@@ -1645,28 +1672,18 @@ float WorldObject::GetSightRange(WorldObject const* target) const
{
if (target)
{
- if (target->IsVisibilityOverridden() && target->IsCreature())
- {
- return *target->m_visibilityDistanceOverride;
- }
+ if (target->IsCreature() && target->IsVisibilityOverridden())
+ return target->GetVisibilityOverrideDistance();
else if (target->IsGameObject())
{
if (IsInWintergrasp() && target->IsInWintergrasp())
- {
- return VISIBILITY_DIST_WINTERGRASP + VISIBILITY_INC_FOR_GOBJECTS;
- }
+ return VISIBILITY_DIST_WINTERGRASP;
else if (target->IsVisibilityOverridden())
- {
- return *target->m_visibilityDistanceOverride;
- }
+ return target->GetVisibilityOverrideDistance();
else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
- {
return DEFAULT_VISIBILITY_INSTANCE;
- }
else
- {
- return GetMap()->GetVisibilityRange() + VISIBILITY_INC_FOR_GOBJECTS;
- }
+ return GetMap()->GetVisibilityRange();
}
return IsInWintergrasp() && target->IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
@@ -1674,19 +1691,13 @@ float WorldObject::GetSightRange(WorldObject const* target) const
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
}
else if (ToCreature())
- {
return ToCreature()->m_SightDistance;
- }
else
- {
return SIGHT_RANGE_UNIT;
- }
}
if (ToDynObject() && isActiveObject())
- {
return GetMap()->GetVisibilityRange();
- }
return 0.0f;
}
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 1a2cdf384f..23784c9c63 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -358,9 +358,20 @@ template<class T>
class GridObject
{
public:
- [[nodiscard]] bool IsInGrid() const { return _gridRef.isValid(); }
- void AddToGrid(GridRefMgr<T>& m) { ASSERT(!IsInGrid()); _gridRef.link(&m, (T*)this); }
- void RemoveFromGrid() { ASSERT(IsInGrid()); _gridRef.unlink(); }
+ bool IsInGrid() const
+ {
+ return _gridRef.isValid();
+ }
+ void AddToGrid(GridRefMgr<T>& m)
+ {
+ ASSERT(!IsInGrid());
+ _gridRef.link(&m, (T*)this);
+ }
+ void RemoveFromGrid()
+ {
+ ASSERT(IsInGrid());
+ _gridRef.unlink();
+ }
private:
GridReference<T> _gridRef;
};
@@ -654,8 +665,11 @@ public:
[[nodiscard]] bool isActiveObject() const { return m_isActive; }
void setActive(bool isActiveObject);
- [[nodiscard]] bool IsFarVisible() const { return m_isFarVisible; }
- [[nodiscard]] bool IsVisibilityOverridden() const { return m_visibilityDistanceOverride.has_value(); }
+ VisibilityDistanceType GetVisibilityOverrideType() const { return _visibilityDistanceOverrideType; }
+ bool IsVisibilityOverridden() const { return _visibilityDistanceOverrideType > VisibilityDistanceType::Normal; }
+ bool IsZoneWideVisible() const { return _visibilityDistanceOverrideType == VisibilityDistanceType::Infinite; }
+ bool IsFarVisible() const { return _visibilityDistanceOverrideType == VisibilityDistanceType::Large || _visibilityDistanceOverrideType == VisibilityDistanceType::Gigantic; }
+ float GetVisibilityOverrideDistance() const;
void SetVisibilityDistanceOverride(VisibilityDistanceType type);
[[nodiscard]] bool IsInWintergrasp() const
@@ -719,8 +733,7 @@ public:
protected:
std::string m_name;
bool m_isActive;
- bool m_isFarVisible;
- Optional<float> m_visibilityDistanceOverride;
+ VisibilityDistanceType _visibilityDistanceOverrideType;
ZoneScript* m_zoneScript;
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const& data);
diff --git a/src/server/game/Entities/Object/ObjectDefines.h b/src/server/game/Entities/Object/ObjectDefines.h
index bfae02203c..fb0daa500b 100644
--- a/src/server/game/Entities/Object/ObjectDefines.h
+++ b/src/server/game/Entities/Object/ObjectDefines.h
@@ -25,7 +25,6 @@
#define ATTACK_DISTANCE 5.0f
#define VISIBILITY_COMPENSATION 15.0f // increase searchers
#define INSPECT_DISTANCE 28.0f
-#define VISIBILITY_INC_FOR_GOBJECTS 30.0f // pussywizard
#define SPELL_SEARCHER_COMPENSATION 30.0f // increase searchers size in case we have large npc near cell border
#define TRADE_DISTANCE 11.11f
#define MAX_VISIBILITY_DISTANCE 250.0f // max distance for visible objects, experimental
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index ebb62dbe51..0700d1140e 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -16311,13 +16311,25 @@ float Player::GetSightRange(WorldObject const* target) const
{
float sightRange = WorldObject::GetSightRange(target);
if (_farSightDistance)
- {
sightRange += *_farSightDistance;
- }
return sightRange;
}
+bool Player::IsWorldObjectOutOfSightRange(WorldObject const* target) const
+{
+ // Special handling for Infinite visibility override objects -> they are zone wide visible
+ if (target->GetVisibilityOverrideType() == VisibilityDistanceType::Infinite)
+ {
+ // Same zone, always visible
+ if (target->GetZoneId() == GetZoneId())
+ return false;
+ }
+
+ // Check if out of range
+ return !m_seer->IsWithinDist(target, GetSightRange(target), true);
+}
+
std::string Player::GetPlayerName()
{
std::string name = GetName();
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index befde718fc..3204f42417 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2630,6 +2630,7 @@ public:
[[nodiscard]] Optional<float> GetFarSightDistance() const;
float GetSightRange(WorldObject const* target = nullptr) const override;
+ bool IsWorldObjectOutOfSightRange(WorldObject const* target) const;
std::string GetPlayerName();
diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp
index 8426e4c8c8..fd41f73aac 100644
--- a/src/server/game/Entities/Player/PlayerUpdates.cpp
+++ b/src/server/game/Entities/Player/PlayerUpdates.cpp
@@ -1594,21 +1594,12 @@ void Player::UpdateVisibilityForPlayer(bool mapChange)
// After added to map seer must be a player - there is no possibility to
// still have different seer (all charm auras must be already removed)
if (mapChange && m_seer != this)
- {
m_seer = this;
- }
-
- Acore::VisibleNotifier notifierNoLarge(
- *this, mapChange,
- false); // visit only objects which are not large; default distance
- Cell::VisitObjects(m_seer, notifierNoLarge,
- GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
- notifierNoLarge.SendToSelf();
- Acore::VisibleNotifier notifierLarge(
- *this, mapChange, true); // visit only large objects; maximum distance
- Cell::VisitObjects(m_seer, notifierLarge, GetSightRange());
- notifierLarge.SendToSelf();
+ Acore::VisibleNotifier notifier(*this, mapChange);
+ Cell::VisitObjects(m_seer, notifier, GetSightRange());
+ Cell::VisitFarVisibleObjects(m_seer, notifier, VISIBILITY_DISTANCE_GIGANTIC);
+ notifier.SendToSelf();
if (mapChange)
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index a2a33e89dc..b5667566e1 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -20284,12 +20284,10 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
//active->m_last_notify_position.Relocate(active->GetPositionX(), active->GetPositionY(), active->GetPositionZ());
}
- Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance
- Cell::VisitObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
- relocateNoLarge.SendToSelf();
- Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance
- Cell::VisitObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE);
- relocateLarge.SendToSelf();
+ Acore::PlayerRelocationNotifier notifier(*player);
+ Cell::VisitObjects(viewPoint, notifier, player->GetSightRange());
+ Cell::VisitFarVisibleObjects(viewPoint, notifier, VISIBILITY_DISTANCE_GIGANTIC);
+ notifier.SendToSelf();
}
if (Player* player = this->ToPlayer())
@@ -20323,16 +20321,10 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
GetMap()->LoadGridsInRange(*player, MAX_VISIBILITY_DISTANCE);
- Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance
- Cell::VisitObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
- relocateNoLarge.SendToSelf();
-
- if (!player->GetFarSightDistance())
- {
- Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance
- Cell::VisitObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE);
- relocateLarge.SendToSelf();
- }
+ Acore::PlayerRelocationNotifier notifier(*player);
+ Cell::VisitObjects(viewPoint, notifier, player->GetSightRange());
+ Cell::VisitFarVisibleObjects(viewPoint, notifier, VISIBILITY_DISTANCE_GIGANTIC);
+ notifier.SendToSelf();
this->AddToNotify(NOTIFY_AI_RELOCATION);
}
@@ -20352,7 +20344,7 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
unit->m_last_notify_position.Relocate(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ());
Acore::CreatureRelocationNotifier relocate(*unit);
- Cell::VisitObjects(unit, relocate, unit->GetVisibilityRange() + VISIBILITY_COMPENSATION);
+ Cell::VisitObjects(unit, relocate, unit->GetVisibilityRange());
this->AddToNotify(NOTIFY_AI_RELOCATION);
}
diff --git a/src/server/game/Grids/Cells/Cell.h b/src/server/game/Grids/Cells/Cell.h
index 89676468d9..a54f7f4cd8 100644
--- a/src/server/game/Grids/Cells/Cell.h
+++ b/src/server/game/Grids/Cells/Cell.h
@@ -106,6 +106,8 @@ struct Cell
template<class T> static void VisitObjects(WorldObject const* obj, T& visitor, float radius);
template<class T> static void VisitObjects(float x, float y, Map* map, T& visitor, float radius);
+ template<class T> static void VisitFarVisibleObjects(WorldObject const* obj, T& visitor, float radius);
+
private:
template<class T, class CONTAINER> void VisitCircle(TypeContainerVisitor<T, CONTAINER>&, Map&, CellCoord const&, CellCoord const&) const;
};
diff --git a/src/server/game/Grids/Cells/CellImpl.h b/src/server/game/Grids/Cells/CellImpl.h
index d3f97a09d2..997840367a 100644
--- a/src/server/game/Grids/Cells/CellImpl.h
+++ b/src/server/game/Grids/Cells/CellImpl.h
@@ -181,4 +181,14 @@ inline void Cell::VisitObjects(float x, float y, Map* map, T& visitor, float rad
cell.Visit(p, gnotifier, *map, x, y, radius);
}
+template<class T>
+inline void Cell::VisitFarVisibleObjects(WorldObject const* center_obj, T& visitor, float radius)
+{
+ CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
+ Cell cell(p);
+
+ TypeContainerVisitor<T, FarVisibleGridContainer> gnotifier(visitor);
+ cell.Visit(p, gnotifier, *center_obj->GetMap(), *center_obj, radius);
+}
+
#endif
diff --git a/src/server/game/Grids/GridCell.h b/src/server/game/Grids/GridCell.h
index 62ff765457..65e3a0315b 100644
--- a/src/server/game/Grids/GridCell.h
+++ b/src/server/game/Grids/GridCell.h
@@ -33,16 +33,20 @@
#include "TypeContainer.h"
#include "TypeContainerVisitor.h"
+class WorldObject;
+
template
<
- class GRID_OBJECT_TYPES
+ class GRID_OBJECT_TYPES,
+ class FAR_VISIBLE_OBJECT_TYPES
>
class GridCell
{
public:
~GridCell() = default;
- template<class SPECIFIC_OBJECT> void AddGridObject(SPECIFIC_OBJECT* obj)
+ template<class SPECIFIC_OBJECT>
+ void AddGridObject(SPECIFIC_OBJECT* obj)
{
_gridObjects.template insert<SPECIFIC_OBJECT>(obj);
ASSERT(obj->IsInGrid());
@@ -50,12 +54,32 @@ public:
// Visit grid objects
template<class T>
- void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES> >& visitor)
+ void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES>>& visitor)
{
visitor.Visit(_gridObjects);
}
+ template<class SPECIFIC_OBJECT>
+ void AddFarVisibleObject(SPECIFIC_OBJECT* obj)
+ {
+ _farVisibleObjects.template Insert<SPECIFIC_OBJECT>(obj);
+ }
+
+ template<class SPECIFIC_OBJECT>
+ void RemoveFarVisibleObject(SPECIFIC_OBJECT* obj)
+ {
+ _farVisibleObjects.template Remove<SPECIFIC_OBJECT>(obj);
+ }
+
+ // Visit far objects
+ template<class T>
+ void Visit(TypeContainerVisitor<T, TypeVectorContainer<FAR_VISIBLE_OBJECT_TYPES>>& visitor)
+ {
+ visitor.Visit(_farVisibleObjects);
+ }
+
private:
TypeMapContainer<GRID_OBJECT_TYPES> _gridObjects;
+ TypeVectorContainer<FAR_VISIBLE_OBJECT_TYPES> _farVisibleObjects;
};
#endif
diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h
index 6918d2b1ae..5c1d09c63e 100644
--- a/src/server/game/Grids/GridDefines.h
+++ b/src/server/game/Grids/GridDefines.h
@@ -57,6 +57,9 @@ typedef TYPELIST_5(GameObject, Player, Creature, Corpse, DynamicObject) AllMapGr
// List of object types stored on map level
typedef TYPELIST_4(Creature, GameObject, DynamicObject, Corpse) AllMapStoredObjectTypes;
+// List of object types that can have far visible range
+typedef TYPELIST_2(Creature, GameObject) AllFarVisibleObjectTypes;
+
typedef GridRefMgr<Corpse> CorpseMapType;
typedef GridRefMgr<Creature> CreatureMapType;
typedef GridRefMgr<DynamicObject> DynamicObjectMapType;
@@ -73,10 +76,11 @@ enum GridMapTypeMask
GRID_MAP_TYPE_MASK_ALL = 0x1F
};
-typedef GridCell<AllMapGridStoredObjectTypes> GridCellType;
-typedef MapGrid<AllMapGridStoredObjectTypes> MapGridType;
+typedef GridCell<AllMapGridStoredObjectTypes, AllFarVisibleObjectTypes> GridCellType;
+typedef MapGrid<AllMapGridStoredObjectTypes, AllFarVisibleObjectTypes> MapGridType;
typedef TypeMapContainer<AllMapGridStoredObjectTypes> GridTypeMapContainer;
+typedef TypeVectorContainer<AllFarVisibleObjectTypes> FarVisibleGridContainer;
typedef TypeUnorderedMapContainer<AllMapStoredObjectTypes, ObjectGuid> MapStoredObjectTypesContainer;
template<uint32 LIMIT>
diff --git a/src/server/game/Grids/MapGrid.h b/src/server/game/Grids/MapGrid.h
index b6dda486c7..c80c3b4d3f 100644
--- a/src/server/game/Grids/MapGrid.h
+++ b/src/server/game/Grids/MapGrid.h
@@ -25,12 +25,13 @@ class GridTerrainData;
template
<
- class GRID_OBJECT_TYPES
+ class GRID_OBJECT_TYPES,
+ class FAR_VISIBLE_OBJECT_TYPES
>
class MapGrid
{
public:
- typedef GridCell<GRID_OBJECT_TYPES> GridCellType;
+ typedef GridCell<GRID_OBJECT_TYPES, FAR_VISIBLE_OBJECT_TYPES> GridCellType;
MapGrid(uint16 const x, uint16 const y)
: _x(x), _y(y), _objectDataLoaded(false), _terrainData(nullptr) { }
@@ -54,9 +55,19 @@ public:
GetOrCreateCell(x, y).RemoveGridObject(obj);
}
+ template<class SPECIFIC_OBJECT> void AddFarVisibleObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
+ {
+ GetOrCreateCell(x, y).AddFarVisibleObject(obj);
+ }
+
+ template<class SPECIFIC_OBJECT> void RemoveFarVisibleObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
+ {
+ GetOrCreateCell(x, y).RemoveFarVisibleObject(obj);
+ }
+
// Visit all cells
template<class T, class TT>
- void VisitAllCells(TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
+ void VisitAllCells(TypeContainerVisitor<T, TT>& visitor)
{
for (auto& cellX : _cells)
{
@@ -72,7 +83,7 @@ public:
// Visit single cell
template<class T, class TT>
- void VisitCell(uint16 const x, uint16 const y, TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
+ void VisitCell(uint16 const x, uint16 const y, TypeContainerVisitor<T, TT>& visitor)
{
GridCellType* gridCell = GetCell(x, y);
if (!gridCell)
@@ -81,7 +92,7 @@ public:
gridCell->Visit(visitor);
}
- void link(GridRefMgr<MapGrid<GRID_OBJECT_TYPES>>* pTo)
+ void link(GridRefMgr<MapGrid<GRID_OBJECT_TYPES, FAR_VISIBLE_OBJECT_TYPES>>* pTo)
{
_gridReference.link(pTo, this);
}
@@ -134,7 +145,7 @@ private:
bool _objectDataLoaded;
std::array<std::array<std::unique_ptr<GridCellType>, MAX_NUMBER_OF_CELLS>, MAX_NUMBER_OF_CELLS> _cells; // N * N array
- GridReference<MapGrid<GRID_OBJECT_TYPES>> _gridReference;
+ GridReference<MapGrid<GRID_OBJECT_TYPES, FAR_VISIBLE_OBJECT_TYPES>> _gridReference;
// Instances will share a copy of the parent maps terrainData
std::shared_ptr<GridTerrainData> _terrainData;
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
index 5636349290..98fdbec76c 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
@@ -29,38 +29,31 @@ void VisibleNotifier::Visit(GameObjectMapType& m)
for (GameObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
GameObject* go = iter->GetSource();
- if (i_largeOnly != go->IsVisibilityOverridden())
- continue;
-
i_player.UpdateVisibilityOf(go, i_data, i_visibleNow);
}
}
void VisibleNotifier::SendToSelf()
{
- // at this moment i_clientGUIDs have guids that not iterate at grid level checks
- // but exist one case when this possible and object not out of range: transports
- if (Transport* transport = i_player.GetTransport())
+ // Update far visible objects
+ ZoneWideVisibleWorldObjectsSet const* zoneWideVisibleObjects = i_player.GetMap()->GetZoneWideVisibleWorldObjectsForZone(i_player.GetZoneId());
+ if (zoneWideVisibleObjects)
{
- for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
+ for (WorldObject* obj : *zoneWideVisibleObjects)
{
- if (i_largeOnly != (*itr)->IsVisibilityOverridden())
- continue;
-
- switch ((*itr)->GetTypeId())
+ switch (obj->GetTypeId())
{
- case TYPEID_GAMEOBJECT:
- i_player.UpdateVisibilityOf((*itr)->ToGameObject(), i_data, i_visibleNow);
- break;
- case TYPEID_PLAYER:
- i_player.UpdateVisibilityOf((*itr)->ToPlayer(), i_data, i_visibleNow);
- (*itr)->ToPlayer()->UpdateVisibilityOf(&i_player);
- break;
- case TYPEID_UNIT:
- i_player.UpdateVisibilityOf((*itr)->ToCreature(), i_data, i_visibleNow);
- break;
- default:
- break;
+ case TYPEID_GAMEOBJECT:
+ i_player.UpdateVisibilityOf(obj->ToGameObject(), i_data, i_visibleNow);
+ break;
+ case TYPEID_UNIT:
+ i_player.UpdateVisibilityOf(obj->ToCreature(), i_data, i_visibleNow);
+ break;
+ case TYPEID_DYNAMICOBJECT:
+ i_player.UpdateVisibilityOf(obj->ToDynObject(), i_data, i_visibleNow);
+ break;
+ default:
+ break;
}
}
}
@@ -69,26 +62,7 @@ void VisibleNotifier::SendToSelf()
for (VisibleWorldObjectsMap::iterator itr = visibleWorldObjects->begin(); itr != visibleWorldObjects->end();)
{
WorldObject* obj = itr->second;
- if (i_largeOnly != obj->IsVisibilityOverridden())
- {
- ++itr;
- continue;
- }
-
- // pussywizard: static transports are removed only in RemovePlayerFromMap and here if can no longer detect (eg. phase changed)
- if (itr->first.IsTransport())
- {
- if (GameObject* staticTrans = obj->ToGameObject())
- {
- if (i_player.CanSeeOrDetect(staticTrans, false, true))
- {
- ++itr;
- continue;
- }
- }
- }
-
- if (i_player.m_seer->IsWithinDist(obj, i_player.GetSightRange(obj), true))
+ if (!i_player.IsWorldObjectOutOfSightRange(obj))
{
++itr;
continue;
@@ -111,12 +85,7 @@ void VisibleNotifier::SendToSelf()
i_player.GetSession()->SendPacket(&packet);
for (std::vector<Unit*>::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it)
- {
- if (i_largeOnly != (*it)->IsVisibilityOverridden())
- continue;
-
i_player.GetInitialVisiblePackets(*it);
- }
}
void VisibleChangesNotifier::Visit(PlayerMapType& m)
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 040c542447..d9556c77f6 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -45,16 +45,16 @@ namespace Acore
Player& i_player;
std::vector<Unit*>& i_visibleNow;
bool i_gobjOnly;
- bool i_largeOnly;
UpdateData i_data;
- VisibleNotifier(Player& player, bool gobjOnly, bool largeOnly) :
- i_player(player), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly), i_largeOnly(largeOnly)
+ VisibleNotifier(Player& player, bool gobjOnly) :
+ i_player(player), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly)
{
i_visibleNow.clear();
}
void Visit(GameObjectMapType&);
+ template<class T> void Visit(std::vector<T>& m);
template<class T> void Visit(GridRefMgr<T>& m);
void SendToSelf(void);
};
@@ -72,8 +72,9 @@ namespace Acore
struct PlayerRelocationNotifier : public VisibleNotifier
{
- PlayerRelocationNotifier(Player& player, bool largeOnly): VisibleNotifier(player, false, largeOnly) { }
+ PlayerRelocationNotifier(Player& player): VisibleNotifier(player, false) { }
+ template<class T> void Visit(std::vector<T>& m) { VisibleNotifier::Visit(m); }
template<class T> void Visit(GridRefMgr<T>& m) { VisibleNotifier::Visit(m); }
void Visit(PlayerMapType&);
};
diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
index 592e584eaf..a24e873745 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
@@ -26,6 +26,13 @@
#include "WorldSession.h"
template<class T>
+inline void Acore::VisibleNotifier::Visit(std::vector<T>& m)
+{
+ for (typename std::vector<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
+ i_player.UpdateVisibilityOf((*iter), i_data, i_visibleNow);
+}
+
+template<class T>
inline void Acore::VisibleNotifier::Visit(GridRefMgr<T>& m)
{
// Xinef: Update gameobjects only
@@ -33,12 +40,7 @@ inline void Acore::VisibleNotifier::Visit(GridRefMgr<T>& m)
return;
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
- {
- if (i_largeOnly != iter->GetSource()->IsVisibilityOverridden())
- continue;
-
i_player.UpdateVisibilityOf(iter->GetSource(), i_data, i_visibleNow);
- }
}
// SEARCHERS & LIST SEARCHERS & WORKERS
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 8e2a0cacff..17ab70da0f 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -118,6 +118,8 @@ void Map::AddToGrid(Creature* obj, Cell const& cell)
{
MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY());
grid->AddGridObject(cell.CellX(), cell.CellY(), obj);
+ if (obj->IsFarVisible())
+ grid->AddFarVisibleObject(cell.CellX(), cell.CellY(), obj);
obj->SetCurrentCell(cell);
}
@@ -127,6 +129,8 @@ void Map::AddToGrid(GameObject* obj, Cell const& cell)
{
MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY());
grid->AddGridObject(cell.CellX(), cell.CellY(), obj);
+ if (obj->IsFarVisible())
+ grid->AddFarVisibleObject(cell.CellX(), cell.CellY(), obj);
obj->SetCurrentCell(cell);
}
@@ -604,6 +608,52 @@ void Map::RemoveObjectFromMapUpdateList(WorldObject* obj)
_RemoveObjectFromUpdateList(obj);
}
+// Used in VisibilityDistanceType::Large and VisibilityDistanceType::Gigantic
+void Map::AddWorldObjectToFarVisibleMap(WorldObject* obj)
+{
+ Cell curr_cell(obj->GetPositionX(), obj->GetPositionY());
+ MapGridType* grid = GetMapGrid(curr_cell.GridX(), curr_cell.GridY());
+
+ if (obj->IsCreature())
+ grid->AddFarVisibleObject(curr_cell.CellX(), curr_cell.CellY(), obj->ToCreature());
+ else if (obj->IsGameObject())
+ grid->AddFarVisibleObject(curr_cell.CellX(), curr_cell.CellY(), obj->ToGameObject());
+}
+
+void Map::RemoveWorldObjectFromFarVisibleMap(WorldObject* obj)
+{
+ Cell curr_cell(obj->GetPositionX(), obj->GetPositionY());
+ MapGridType* grid = GetMapGrid(curr_cell.GridX(), curr_cell.GridY());
+ if (obj->IsCreature())
+ grid->RemoveFarVisibleObject(curr_cell.CellX(), curr_cell.CellY(), obj->ToCreature());
+ else if (obj->IsGameObject())
+ grid->RemoveFarVisibleObject(curr_cell.CellX(), curr_cell.CellY(), obj->ToGameObject());
+}
+
+// Used in VisibilityDistanceType::Infinite
+void Map::AddWorldObjectToZoneWideVisibleMap(uint32 zoneId, WorldObject* obj)
+{
+ _zoneWideVisibleWorldObjectsMap[zoneId].insert(obj);
+}
+
+void Map::RemoveWorldObjectFromZoneWideVisibleMap(uint32 zoneId, WorldObject* obj)
+{
+ ZoneWideVisibleWorldObjectsMap::iterator itr = _zoneWideVisibleWorldObjectsMap.find(zoneId);
+ if (itr == _zoneWideVisibleWorldObjectsMap.end())
+ return;
+
+ itr->second.erase(obj);
+}
+
+ZoneWideVisibleWorldObjectsSet const* Map::GetZoneWideVisibleWorldObjectsForZone(uint32 zoneId) const
+{
+ ZoneWideVisibleWorldObjectsMap::const_iterator itr = _zoneWideVisibleWorldObjectsMap.find(zoneId);
+ if (itr == _zoneWideVisibleWorldObjectsMap.end())
+ return nullptr;
+
+ return &itr->second;
+}
+
void Map::HandleDelayedVisibility()
{
if (i_objectsForDelayedVisibility.empty())
@@ -656,6 +706,8 @@ void Map::RemoveFromMap(T* obj, bool remove)
obj->RemoveFromWorld();
obj->RemoveFromGrid();
+ if (obj->IsFarVisible())
+ RemoveWorldObjectFromFarVisibleMap(obj);
obj->ResetMap();
@@ -852,6 +904,12 @@ void Map::MoveAllCreaturesInMoveList()
Cell const& old_cell = c->GetCurrentCell();
Cell new_cell(c->GetPositionX(), c->GetPositionY());
+ MapGridType* oldGrid = GetMapGrid(old_cell.GridX(), old_cell.GridY());
+ if (c->IsFarVisible())
+ {
+ oldGrid->RemoveFarVisibleObject(old_cell.CellX(), old_cell.CellY(), c);
+ AddWorldObjectToFarVisibleMap(c);
+ }
c->RemoveFromGrid();
if (old_cell.DiffGrid(new_cell))
@@ -881,6 +939,12 @@ void Map::MoveAllGameObjectsInMoveList()
Cell const& old_cell = go->GetCurrentCell();
Cell new_cell(go->GetPositionX(), go->GetPositionY());
+ MapGridType* oldGrid = GetMapGrid(old_cell.GridX(), old_cell.GridY());
+ if (go->IsFarVisible())
+ {
+ oldGrid->RemoveFarVisibleObject(old_cell.CellX(), old_cell.CellY(), go);
+ AddWorldObjectToFarVisibleMap(go);
+ }
go->RemoveFromGrid();
if (old_cell.DiffGrid(new_cell))
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 2e5b0ed0a6..c875e4eaa9 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -147,6 +147,8 @@ struct ZoneDynamicInfo
typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
typedef std::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap;
typedef std::unordered_set<Transport*> TransportsContainer;
+typedef std::unordered_set<WorldObject*> ZoneWideVisibleWorldObjectsSet;
+typedef std::unordered_map<uint32 /*ZoneId*/, ZoneWideVisibleWorldObjectsSet> ZoneWideVisibleWorldObjectsMap;
enum EncounterCreditType : uint8
{
@@ -496,6 +498,12 @@ public:
typedef std::vector<WorldObject*> UpdatableObjectList;
typedef std::unordered_set<WorldObject*> PendingAddUpdatableObjectList;
+ void AddWorldObjectToFarVisibleMap(WorldObject* obj);
+ void RemoveWorldObjectFromFarVisibleMap(WorldObject* obj);
+ void AddWorldObjectToZoneWideVisibleMap(uint32 zoneId, WorldObject* obj);
+ void RemoveWorldObjectFromZoneWideVisibleMap(uint32 zoneId, WorldObject* obj);
+ ZoneWideVisibleWorldObjectsSet const* GetZoneWideVisibleWorldObjectsForZone(uint32 zoneId) const;
+
private:
template<class T> void InitializeObject(T* obj);
@@ -603,6 +611,7 @@ private:
UpdatableObjectList _updatableObjectList;
PendingAddUpdatableObjectList _pendingAddUpdatableObjectList;
IntervalTimer _updatableObjectListRecheckTimer;
+ ZoneWideVisibleWorldObjectsMap _zoneWideVisibleWorldObjectsMap;
};
enum InstanceResetMethod
diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp
index a18e01e0bd..40bb89b93b 100644
--- a/src/server/scripts/Commands/cs_debug.cpp
+++ b/src/server/scripts/Commands/cs_debug.cpp
@@ -99,7 +99,8 @@ public:
{ "objectcount", HandleDebugObjectCountCommand, SEC_ADMINISTRATOR, Console::Yes},
{ "dummy", HandleDebugDummyCommand, SEC_ADMINISTRATOR, Console::No },
{ "mapdata", HandleDebugMapDataCommand, SEC_ADMINISTRATOR, Console::No },
- { "boundary", HandleDebugBoundaryCommand, SEC_ADMINISTRATOR, Console::No }
+ { "boundary", HandleDebugBoundaryCommand, SEC_ADMINISTRATOR, Console::No },
+ { "visibilitydata", HandleDebugVisibilityDataCommand, SEC_ADMINISTRATOR, Console::No }
};
static ChatCommandTable commandTable =
{
@@ -1403,6 +1404,36 @@ public:
return true;
}
+
+ static bool HandleDebugVisibilityDataCommand(ChatHandler* handler)
+ {
+ Player* player = handler->GetPlayer();
+ if (!player)
+ return false;
+
+ std::array<uint32, NUM_CLIENT_OBJECT_TYPES> objectByTypeCount = {};
+
+ ObjectVisibilityContainer const& objectVisibilityContainer = player->GetObjectVisibilityContainer();
+ for (auto const& kvPair : *objectVisibilityContainer.GetVisibleWorldObjectsMap())
+ {
+ WorldObject const* obj = kvPair.second;
+ ++objectByTypeCount[obj->GetTypeId()];
+ }
+
+ uint32 zoneWideVisibleObjectsInZone = 0;
+ if (ZoneWideVisibleWorldObjectsSet const* farVisibleSet = player->GetMap()->GetZoneWideVisibleWorldObjectsForZone(player->GetZoneId()))
+ zoneWideVisibleObjectsInZone = farVisibleSet->size();
+
+ handler->PSendSysMessage("Visibility Range: {}", player->GetVisibilityRange());
+ handler->PSendSysMessage("Visible Creatures: {}", objectByTypeCount[TYPEID_UNIT]);
+ handler->PSendSysMessage("Visible Players: {}", objectByTypeCount[TYPEID_PLAYER]);
+ handler->PSendSysMessage("Visible GameObjects: {}", objectByTypeCount[TYPEID_GAMEOBJECT]);
+ handler->PSendSysMessage("Visible DynamicObjects: {}", objectByTypeCount[TYPEID_DYNAMICOBJECT]);
+ handler->PSendSysMessage("Visible Corpses: {}", objectByTypeCount[TYPEID_CORPSE]);
+ handler->PSendSysMessage("Players we are visible to: {}", objectVisibilityContainer.GetVisiblePlayersMap().size());
+ handler->PSendSysMessage("Zone wide visible objects in zone: {}", zoneWideVisibleObjectsInZone);
+ return true;
+ }
};
void AddSC_debug_commandscript()