feat(Core/Visibility): Far visibility worldobjects (#22828)
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
#include "Dynamic/TypeList.h"
|
#include "Dynamic/TypeList.h"
|
||||||
#include "GridRefMgr.h"
|
#include "GridRefMgr.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @class ContainerMapList is a mulit-type container for map elements
|
* @class ContainerMapList is a mulit-type container for map elements
|
||||||
@@ -50,6 +51,24 @@ struct ContainerMapList<TypeList<H, T>>
|
|||||||
ContainerMapList<T> _TailElements;
|
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>
|
template<class OBJECT, class KEY_TYPE>
|
||||||
struct ContainerUnorderedMap
|
struct ContainerUnorderedMap
|
||||||
{
|
{
|
||||||
@@ -123,6 +142,33 @@ private:
|
|||||||
ContainerMapList<OBJECT_TYPES> i_elements;
|
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>
|
template<class OBJECT_TYPES, class KEY_TYPE>
|
||||||
class TypeUnorderedMapContainer
|
class TypeUnorderedMapContainer
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -239,5 +239,101 @@ namespace Acore
|
|||||||
// SPECIFIC_TYPE* t = Remove(elements._elements, obj);
|
// SPECIFIC_TYPE* t = Remove(elements._elements, obj);
|
||||||
// return ( t != nullptr ? t : Remove(elements._TailElements, 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
|
#endif
|
||||||
|
|||||||
@@ -56,6 +56,27 @@ template<class VISITOR, class OBJECT_TYPES> void VisitorHelper(VISITOR& v, TypeM
|
|||||||
VisitorHelper(v, c.GetElements());
|
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
|
// TypeUnorderedMapContainer
|
||||||
template<class VISITOR, class KEY_TYPE>
|
template<class VISITOR, class KEY_TYPE>
|
||||||
void VisitorHelper(VISITOR& /*v*/, ContainerUnorderedMap<TypeNull, KEY_TYPE>& /*c*/) { }
|
void VisitorHelper(VISITOR& /*v*/, ContainerUnorderedMap<TypeNull, KEY_TYPE>& /*c*/) { }
|
||||||
|
|||||||
@@ -431,15 +431,11 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
|
|||||||
|
|
||||||
// Check if GameObject is Large
|
// Check if GameObject is Large
|
||||||
if (goinfo->IsLargeGameObject())
|
if (goinfo->IsLargeGameObject())
|
||||||
{
|
|
||||||
SetVisibilityDistanceOverride(VisibilityDistanceType::Large);
|
SetVisibilityDistanceOverride(VisibilityDistanceType::Large);
|
||||||
}
|
|
||||||
|
|
||||||
// Check if GameObject is Infinite
|
// Check if GameObject is Infinite
|
||||||
if (goinfo->IsInfiniteGameObject())
|
if (goinfo->IsInfiniteGameObject())
|
||||||
{
|
|
||||||
SetVisibilityDistanceOverride(VisibilityDistanceType::Infinite);
|
SetVisibilityDistanceOverride(VisibilityDistanceType::Infinite);
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1037,7 +1037,7 @@ void MovementInfo::OutDebug()
|
|||||||
}
|
}
|
||||||
|
|
||||||
WorldObject::WorldObject() : WorldLocation(),
|
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),
|
_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_currMap(nullptr), _heartbeatTimer(HEARTBEAT_INTERVAL), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true),
|
||||||
m_notifyflags(0), m_executed_notifies(0), _objectVisibilityContainer(this)
|
m_notifyflags(0), m_executed_notifies(0), _objectVisibilityContainer(this)
|
||||||
@@ -1082,15 +1082,36 @@ void WorldObject::setActive(bool on)
|
|||||||
map->AddObjectToPendingUpdateList(this);
|
map->AddObjectToPendingUpdateList(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float WorldObject::GetVisibilityOverrideDistance() const
|
||||||
|
{
|
||||||
|
ASSERT(_visibilityDistanceOverrideType < VisibilityDistanceType::Max);
|
||||||
|
return VisibilityDistances[AsUnderlyingType(_visibilityDistanceOverrideType)];
|
||||||
|
}
|
||||||
|
|
||||||
void WorldObject::SetVisibilityDistanceOverride(VisibilityDistanceType type)
|
void WorldObject::SetVisibilityDistanceOverride(VisibilityDistanceType type)
|
||||||
{
|
{
|
||||||
ASSERT(type < VisibilityDistanceType::Max);
|
ASSERT(type < VisibilityDistanceType::Max);
|
||||||
if (IsPlayer())
|
|
||||||
{
|
if (type == GetVisibilityOverrideType())
|
||||||
return;
|
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*/)
|
void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
|
||||||
@@ -1127,6 +1148,8 @@ void WorldObject::UpdatePositionData()
|
|||||||
|
|
||||||
void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
|
void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
|
||||||
{
|
{
|
||||||
|
uint32 const oldZoneId = _zoneId;
|
||||||
|
|
||||||
_zoneId = _areaId = data.areaId;
|
_zoneId = _areaId = data.areaId;
|
||||||
|
|
||||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(_areaId))
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(_areaId))
|
||||||
@@ -1136,6 +1159,17 @@ void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& da
|
|||||||
_outdoors = data.outdoors;
|
_outdoors = data.outdoors;
|
||||||
_floorZ = data.floorZ;
|
_floorZ = data.floorZ;
|
||||||
_liquidData = data.liquidInfo;
|
_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()
|
void WorldObject::AddToWorld()
|
||||||
@@ -1150,6 +1184,9 @@ void WorldObject::RemoveFromWorld()
|
|||||||
if (!IsInWorld())
|
if (!IsInWorld())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (IsZoneWideVisible())
|
||||||
|
GetMap()->RemoveWorldObjectFromZoneWideVisibleMap(GetZoneId(), this);
|
||||||
|
|
||||||
DestroyForVisiblePlayers();
|
DestroyForVisiblePlayers();
|
||||||
|
|
||||||
GetObjectVisibilityContainer().CleanVisibilityReferences();
|
GetObjectVisibilityContainer().CleanVisibilityReferences();
|
||||||
@@ -1612,26 +1649,16 @@ float WorldObject::GetGridActivationRange() const
|
|||||||
|
|
||||||
float WorldObject::GetVisibilityRange() const
|
float WorldObject::GetVisibilityRange() const
|
||||||
{
|
{
|
||||||
if (IsVisibilityOverridden() && IsCreature())
|
if (IsCreature() && IsVisibilityOverridden())
|
||||||
{
|
return GetVisibilityOverrideDistance();
|
||||||
return *m_visibilityDistanceOverride;
|
|
||||||
}
|
|
||||||
else if (IsGameObject())
|
else if (IsGameObject())
|
||||||
{
|
{
|
||||||
{
|
if (IsInWintergrasp())
|
||||||
if (IsInWintergrasp())
|
return VISIBILITY_DIST_WINTERGRASP;
|
||||||
{
|
else if (IsVisibilityOverridden())
|
||||||
return VISIBILITY_DIST_WINTERGRASP + VISIBILITY_INC_FOR_GOBJECTS;
|
return GetVisibilityOverrideDistance();
|
||||||
}
|
else
|
||||||
else if (IsVisibilityOverridden())
|
return GetMap()->GetVisibilityRange();
|
||||||
{
|
|
||||||
return *m_visibilityDistanceOverride;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return GetMap()->GetVisibilityRange() + VISIBILITY_INC_FOR_GOBJECTS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
|
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
|
||||||
@@ -1645,28 +1672,18 @@ float WorldObject::GetSightRange(WorldObject const* target) const
|
|||||||
{
|
{
|
||||||
if (target)
|
if (target)
|
||||||
{
|
{
|
||||||
if (target->IsVisibilityOverridden() && target->IsCreature())
|
if (target->IsCreature() && target->IsVisibilityOverridden())
|
||||||
{
|
return target->GetVisibilityOverrideDistance();
|
||||||
return *target->m_visibilityDistanceOverride;
|
|
||||||
}
|
|
||||||
else if (target->IsGameObject())
|
else if (target->IsGameObject())
|
||||||
{
|
{
|
||||||
if (IsInWintergrasp() && target->IsInWintergrasp())
|
if (IsInWintergrasp() && target->IsInWintergrasp())
|
||||||
{
|
return VISIBILITY_DIST_WINTERGRASP;
|
||||||
return VISIBILITY_DIST_WINTERGRASP + VISIBILITY_INC_FOR_GOBJECTS;
|
|
||||||
}
|
|
||||||
else if (target->IsVisibilityOverridden())
|
else if (target->IsVisibilityOverridden())
|
||||||
{
|
return target->GetVisibilityOverrideDistance();
|
||||||
return *target->m_visibilityDistanceOverride;
|
|
||||||
}
|
|
||||||
else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
|
else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
|
||||||
{
|
|
||||||
return DEFAULT_VISIBILITY_INSTANCE;
|
return DEFAULT_VISIBILITY_INSTANCE;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
return GetMap()->GetVisibilityRange();
|
||||||
return GetMap()->GetVisibilityRange() + VISIBILITY_INC_FOR_GOBJECTS;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return IsInWintergrasp() && target->IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : 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();
|
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
|
||||||
}
|
}
|
||||||
else if (ToCreature())
|
else if (ToCreature())
|
||||||
{
|
|
||||||
return ToCreature()->m_SightDistance;
|
return ToCreature()->m_SightDistance;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return SIGHT_RANGE_UNIT;
|
return SIGHT_RANGE_UNIT;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ToDynObject() && isActiveObject())
|
if (ToDynObject() && isActiveObject())
|
||||||
{
|
|
||||||
return GetMap()->GetVisibilityRange();
|
return GetMap()->GetVisibilityRange();
|
||||||
}
|
|
||||||
|
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -358,9 +358,20 @@ template<class T>
|
|||||||
class GridObject
|
class GridObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] bool IsInGrid() const { return _gridRef.isValid(); }
|
bool IsInGrid() const
|
||||||
void AddToGrid(GridRefMgr<T>& m) { ASSERT(!IsInGrid()); _gridRef.link(&m, (T*)this); }
|
{
|
||||||
void RemoveFromGrid() { ASSERT(IsInGrid()); _gridRef.unlink(); }
|
return _gridRef.isValid();
|
||||||
|
}
|
||||||
|
void AddToGrid(GridRefMgr<T>& m)
|
||||||
|
{
|
||||||
|
ASSERT(!IsInGrid());
|
||||||
|
_gridRef.link(&m, (T*)this);
|
||||||
|
}
|
||||||
|
void RemoveFromGrid()
|
||||||
|
{
|
||||||
|
ASSERT(IsInGrid());
|
||||||
|
_gridRef.unlink();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
GridReference<T> _gridRef;
|
GridReference<T> _gridRef;
|
||||||
};
|
};
|
||||||
@@ -654,8 +665,11 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] bool isActiveObject() const { return m_isActive; }
|
[[nodiscard]] bool isActiveObject() const { return m_isActive; }
|
||||||
void setActive(bool isActiveObject);
|
void setActive(bool isActiveObject);
|
||||||
[[nodiscard]] bool IsFarVisible() const { return m_isFarVisible; }
|
VisibilityDistanceType GetVisibilityOverrideType() const { return _visibilityDistanceOverrideType; }
|
||||||
[[nodiscard]] bool IsVisibilityOverridden() const { return m_visibilityDistanceOverride.has_value(); }
|
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);
|
void SetVisibilityDistanceOverride(VisibilityDistanceType type);
|
||||||
|
|
||||||
[[nodiscard]] bool IsInWintergrasp() const
|
[[nodiscard]] bool IsInWintergrasp() const
|
||||||
@@ -719,8 +733,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
bool m_isActive;
|
bool m_isActive;
|
||||||
bool m_isFarVisible;
|
VisibilityDistanceType _visibilityDistanceOverrideType;
|
||||||
Optional<float> m_visibilityDistanceOverride;
|
|
||||||
ZoneScript* m_zoneScript;
|
ZoneScript* m_zoneScript;
|
||||||
|
|
||||||
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const& data);
|
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const& data);
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#define ATTACK_DISTANCE 5.0f
|
#define ATTACK_DISTANCE 5.0f
|
||||||
#define VISIBILITY_COMPENSATION 15.0f // increase searchers
|
#define VISIBILITY_COMPENSATION 15.0f // increase searchers
|
||||||
#define INSPECT_DISTANCE 28.0f
|
#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 SPELL_SEARCHER_COMPENSATION 30.0f // increase searchers size in case we have large npc near cell border
|
||||||
#define TRADE_DISTANCE 11.11f
|
#define TRADE_DISTANCE 11.11f
|
||||||
#define MAX_VISIBILITY_DISTANCE 250.0f // max distance for visible objects, experimental
|
#define MAX_VISIBILITY_DISTANCE 250.0f // max distance for visible objects, experimental
|
||||||
|
|||||||
@@ -16311,13 +16311,25 @@ float Player::GetSightRange(WorldObject const* target) const
|
|||||||
{
|
{
|
||||||
float sightRange = WorldObject::GetSightRange(target);
|
float sightRange = WorldObject::GetSightRange(target);
|
||||||
if (_farSightDistance)
|
if (_farSightDistance)
|
||||||
{
|
|
||||||
sightRange += *_farSightDistance;
|
sightRange += *_farSightDistance;
|
||||||
}
|
|
||||||
|
|
||||||
return sightRange;
|
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 Player::GetPlayerName()
|
||||||
{
|
{
|
||||||
std::string name = GetName();
|
std::string name = GetName();
|
||||||
|
|||||||
@@ -2630,6 +2630,7 @@ public:
|
|||||||
[[nodiscard]] Optional<float> GetFarSightDistance() const;
|
[[nodiscard]] Optional<float> GetFarSightDistance() const;
|
||||||
|
|
||||||
float GetSightRange(WorldObject const* target = nullptr) const override;
|
float GetSightRange(WorldObject const* target = nullptr) const override;
|
||||||
|
bool IsWorldObjectOutOfSightRange(WorldObject const* target) const;
|
||||||
|
|
||||||
std::string GetPlayerName();
|
std::string GetPlayerName();
|
||||||
|
|
||||||
|
|||||||
@@ -1594,21 +1594,12 @@ void Player::UpdateVisibilityForPlayer(bool mapChange)
|
|||||||
// After added to map seer must be a player - there is no possibility to
|
// 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)
|
// still have different seer (all charm auras must be already removed)
|
||||||
if (mapChange && m_seer != this)
|
if (mapChange && m_seer != this)
|
||||||
{
|
|
||||||
m_seer = this;
|
m_seer = this;
|
||||||
}
|
|
||||||
|
|
||||||
Acore::VisibleNotifier notifierNoLarge(
|
Acore::VisibleNotifier notifier(*this, mapChange);
|
||||||
*this, mapChange,
|
Cell::VisitObjects(m_seer, notifier, GetSightRange());
|
||||||
false); // visit only objects which are not large; default distance
|
Cell::VisitFarVisibleObjects(m_seer, notifier, VISIBILITY_DISTANCE_GIGANTIC);
|
||||||
Cell::VisitObjects(m_seer, notifierNoLarge,
|
notifier.SendToSelf();
|
||||||
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();
|
|
||||||
|
|
||||||
if (mapChange)
|
if (mapChange)
|
||||||
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
||||||
|
|||||||
@@ -20284,12 +20284,10 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
|
|||||||
//active->m_last_notify_position.Relocate(active->GetPositionX(), active->GetPositionY(), active->GetPositionZ());
|
//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
|
Acore::PlayerRelocationNotifier notifier(*player);
|
||||||
Cell::VisitObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
|
Cell::VisitObjects(viewPoint, notifier, player->GetSightRange());
|
||||||
relocateNoLarge.SendToSelf();
|
Cell::VisitFarVisibleObjects(viewPoint, notifier, VISIBILITY_DISTANCE_GIGANTIC);
|
||||||
Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance
|
notifier.SendToSelf();
|
||||||
Cell::VisitObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE);
|
|
||||||
relocateLarge.SendToSelf();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Player* player = this->ToPlayer())
|
if (Player* player = this->ToPlayer())
|
||||||
@@ -20323,16 +20321,10 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
|
|||||||
|
|
||||||
GetMap()->LoadGridsInRange(*player, MAX_VISIBILITY_DISTANCE);
|
GetMap()->LoadGridsInRange(*player, MAX_VISIBILITY_DISTANCE);
|
||||||
|
|
||||||
Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance
|
Acore::PlayerRelocationNotifier notifier(*player);
|
||||||
Cell::VisitObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
|
Cell::VisitObjects(viewPoint, notifier, player->GetSightRange());
|
||||||
relocateNoLarge.SendToSelf();
|
Cell::VisitFarVisibleObjects(viewPoint, notifier, VISIBILITY_DISTANCE_GIGANTIC);
|
||||||
|
notifier.SendToSelf();
|
||||||
if (!player->GetFarSightDistance())
|
|
||||||
{
|
|
||||||
Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance
|
|
||||||
Cell::VisitObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE);
|
|
||||||
relocateLarge.SendToSelf();
|
|
||||||
}
|
|
||||||
|
|
||||||
this->AddToNotify(NOTIFY_AI_RELOCATION);
|
this->AddToNotify(NOTIFY_AI_RELOCATION);
|
||||||
}
|
}
|
||||||
@@ -20352,7 +20344,7 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
|
|||||||
unit->m_last_notify_position.Relocate(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ());
|
unit->m_last_notify_position.Relocate(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ());
|
||||||
|
|
||||||
Acore::CreatureRelocationNotifier relocate(*unit);
|
Acore::CreatureRelocationNotifier relocate(*unit);
|
||||||
Cell::VisitObjects(unit, relocate, unit->GetVisibilityRange() + VISIBILITY_COMPENSATION);
|
Cell::VisitObjects(unit, relocate, unit->GetVisibilityRange());
|
||||||
|
|
||||||
this->AddToNotify(NOTIFY_AI_RELOCATION);
|
this->AddToNotify(NOTIFY_AI_RELOCATION);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(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 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:
|
private:
|
||||||
template<class T, class CONTAINER> void VisitCircle(TypeContainerVisitor<T, CONTAINER>&, Map&, CellCoord const&, CellCoord const&) const;
|
template<class T, class CONTAINER> void VisitCircle(TypeContainerVisitor<T, CONTAINER>&, Map&, CellCoord const&, CellCoord const&) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
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
|
#endif
|
||||||
|
|||||||
@@ -33,16 +33,20 @@
|
|||||||
#include "TypeContainer.h"
|
#include "TypeContainer.h"
|
||||||
#include "TypeContainerVisitor.h"
|
#include "TypeContainerVisitor.h"
|
||||||
|
|
||||||
|
class WorldObject;
|
||||||
|
|
||||||
template
|
template
|
||||||
<
|
<
|
||||||
class GRID_OBJECT_TYPES
|
class GRID_OBJECT_TYPES,
|
||||||
|
class FAR_VISIBLE_OBJECT_TYPES
|
||||||
>
|
>
|
||||||
class GridCell
|
class GridCell
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~GridCell() = default;
|
~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);
|
_gridObjects.template insert<SPECIFIC_OBJECT>(obj);
|
||||||
ASSERT(obj->IsInGrid());
|
ASSERT(obj->IsInGrid());
|
||||||
@@ -50,12 +54,32 @@ public:
|
|||||||
|
|
||||||
// Visit grid objects
|
// Visit grid objects
|
||||||
template<class T>
|
template<class T>
|
||||||
void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES> >& visitor)
|
void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES>>& visitor)
|
||||||
{
|
{
|
||||||
visitor.Visit(_gridObjects);
|
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:
|
private:
|
||||||
TypeMapContainer<GRID_OBJECT_TYPES> _gridObjects;
|
TypeMapContainer<GRID_OBJECT_TYPES> _gridObjects;
|
||||||
|
TypeVectorContainer<FAR_VISIBLE_OBJECT_TYPES> _farVisibleObjects;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ typedef TYPELIST_5(GameObject, Player, Creature, Corpse, DynamicObject) AllMapGr
|
|||||||
// List of object types stored on map level
|
// List of object types stored on map level
|
||||||
typedef TYPELIST_4(Creature, GameObject, DynamicObject, Corpse) AllMapStoredObjectTypes;
|
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<Corpse> CorpseMapType;
|
||||||
typedef GridRefMgr<Creature> CreatureMapType;
|
typedef GridRefMgr<Creature> CreatureMapType;
|
||||||
typedef GridRefMgr<DynamicObject> DynamicObjectMapType;
|
typedef GridRefMgr<DynamicObject> DynamicObjectMapType;
|
||||||
@@ -73,10 +76,11 @@ enum GridMapTypeMask
|
|||||||
GRID_MAP_TYPE_MASK_ALL = 0x1F
|
GRID_MAP_TYPE_MASK_ALL = 0x1F
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef GridCell<AllMapGridStoredObjectTypes> GridCellType;
|
typedef GridCell<AllMapGridStoredObjectTypes, AllFarVisibleObjectTypes> GridCellType;
|
||||||
typedef MapGrid<AllMapGridStoredObjectTypes> MapGridType;
|
typedef MapGrid<AllMapGridStoredObjectTypes, AllFarVisibleObjectTypes> MapGridType;
|
||||||
|
|
||||||
typedef TypeMapContainer<AllMapGridStoredObjectTypes> GridTypeMapContainer;
|
typedef TypeMapContainer<AllMapGridStoredObjectTypes> GridTypeMapContainer;
|
||||||
|
typedef TypeVectorContainer<AllFarVisibleObjectTypes> FarVisibleGridContainer;
|
||||||
typedef TypeUnorderedMapContainer<AllMapStoredObjectTypes, ObjectGuid> MapStoredObjectTypesContainer;
|
typedef TypeUnorderedMapContainer<AllMapStoredObjectTypes, ObjectGuid> MapStoredObjectTypesContainer;
|
||||||
|
|
||||||
template<uint32 LIMIT>
|
template<uint32 LIMIT>
|
||||||
|
|||||||
@@ -25,12 +25,13 @@ class GridTerrainData;
|
|||||||
|
|
||||||
template
|
template
|
||||||
<
|
<
|
||||||
class GRID_OBJECT_TYPES
|
class GRID_OBJECT_TYPES,
|
||||||
|
class FAR_VISIBLE_OBJECT_TYPES
|
||||||
>
|
>
|
||||||
class MapGrid
|
class MapGrid
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef GridCell<GRID_OBJECT_TYPES> GridCellType;
|
typedef GridCell<GRID_OBJECT_TYPES, FAR_VISIBLE_OBJECT_TYPES> GridCellType;
|
||||||
|
|
||||||
MapGrid(uint16 const x, uint16 const y)
|
MapGrid(uint16 const x, uint16 const y)
|
||||||
: _x(x), _y(y), _objectDataLoaded(false), _terrainData(nullptr) { }
|
: _x(x), _y(y), _objectDataLoaded(false), _terrainData(nullptr) { }
|
||||||
@@ -54,9 +55,19 @@ public:
|
|||||||
GetOrCreateCell(x, y).RemoveGridObject(obj);
|
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
|
// Visit all cells
|
||||||
template<class T, class TT>
|
template<class T, class TT>
|
||||||
void VisitAllCells(TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
|
void VisitAllCells(TypeContainerVisitor<T, TT>& visitor)
|
||||||
{
|
{
|
||||||
for (auto& cellX : _cells)
|
for (auto& cellX : _cells)
|
||||||
{
|
{
|
||||||
@@ -72,7 +83,7 @@ public:
|
|||||||
|
|
||||||
// Visit single cell
|
// Visit single cell
|
||||||
template<class T, class TT>
|
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);
|
GridCellType* gridCell = GetCell(x, y);
|
||||||
if (!gridCell)
|
if (!gridCell)
|
||||||
@@ -81,7 +92,7 @@ public:
|
|||||||
gridCell->Visit(visitor);
|
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);
|
_gridReference.link(pTo, this);
|
||||||
}
|
}
|
||||||
@@ -134,7 +145,7 @@ private:
|
|||||||
|
|
||||||
bool _objectDataLoaded;
|
bool _objectDataLoaded;
|
||||||
std::array<std::array<std::unique_ptr<GridCellType>, MAX_NUMBER_OF_CELLS>, MAX_NUMBER_OF_CELLS> _cells; // N * N array
|
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
|
// Instances will share a copy of the parent maps terrainData
|
||||||
std::shared_ptr<GridTerrainData> _terrainData;
|
std::shared_ptr<GridTerrainData> _terrainData;
|
||||||
|
|||||||
@@ -29,38 +29,31 @@ void VisibleNotifier::Visit(GameObjectMapType& m)
|
|||||||
for (GameObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
for (GameObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||||
{
|
{
|
||||||
GameObject* go = iter->GetSource();
|
GameObject* go = iter->GetSource();
|
||||||
if (i_largeOnly != go->IsVisibilityOverridden())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
i_player.UpdateVisibilityOf(go, i_data, i_visibleNow);
|
i_player.UpdateVisibilityOf(go, i_data, i_visibleNow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisibleNotifier::SendToSelf()
|
void VisibleNotifier::SendToSelf()
|
||||||
{
|
{
|
||||||
// at this moment i_clientGUIDs have guids that not iterate at grid level checks
|
// Update far visible objects
|
||||||
// but exist one case when this possible and object not out of range: transports
|
ZoneWideVisibleWorldObjectsSet const* zoneWideVisibleObjects = i_player.GetMap()->GetZoneWideVisibleWorldObjectsForZone(i_player.GetZoneId());
|
||||||
if (Transport* transport = i_player.GetTransport())
|
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())
|
switch (obj->GetTypeId())
|
||||||
continue;
|
|
||||||
|
|
||||||
switch ((*itr)->GetTypeId())
|
|
||||||
{
|
{
|
||||||
case TYPEID_GAMEOBJECT:
|
case TYPEID_GAMEOBJECT:
|
||||||
i_player.UpdateVisibilityOf((*itr)->ToGameObject(), i_data, i_visibleNow);
|
i_player.UpdateVisibilityOf(obj->ToGameObject(), i_data, i_visibleNow);
|
||||||
break;
|
break;
|
||||||
case TYPEID_PLAYER:
|
case TYPEID_UNIT:
|
||||||
i_player.UpdateVisibilityOf((*itr)->ToPlayer(), i_data, i_visibleNow);
|
i_player.UpdateVisibilityOf(obj->ToCreature(), i_data, i_visibleNow);
|
||||||
(*itr)->ToPlayer()->UpdateVisibilityOf(&i_player);
|
break;
|
||||||
break;
|
case TYPEID_DYNAMICOBJECT:
|
||||||
case TYPEID_UNIT:
|
i_player.UpdateVisibilityOf(obj->ToDynObject(), i_data, i_visibleNow);
|
||||||
i_player.UpdateVisibilityOf((*itr)->ToCreature(), i_data, i_visibleNow);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,26 +62,7 @@ void VisibleNotifier::SendToSelf()
|
|||||||
for (VisibleWorldObjectsMap::iterator itr = visibleWorldObjects->begin(); itr != visibleWorldObjects->end();)
|
for (VisibleWorldObjectsMap::iterator itr = visibleWorldObjects->begin(); itr != visibleWorldObjects->end();)
|
||||||
{
|
{
|
||||||
WorldObject* obj = itr->second;
|
WorldObject* obj = itr->second;
|
||||||
if (i_largeOnly != obj->IsVisibilityOverridden())
|
if (!i_player.IsWorldObjectOutOfSightRange(obj))
|
||||||
{
|
|
||||||
++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))
|
|
||||||
{
|
{
|
||||||
++itr;
|
++itr;
|
||||||
continue;
|
continue;
|
||||||
@@ -111,12 +85,7 @@ void VisibleNotifier::SendToSelf()
|
|||||||
i_player.GetSession()->SendPacket(&packet);
|
i_player.GetSession()->SendPacket(&packet);
|
||||||
|
|
||||||
for (std::vector<Unit*>::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it)
|
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);
|
i_player.GetInitialVisiblePackets(*it);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisibleChangesNotifier::Visit(PlayerMapType& m)
|
void VisibleChangesNotifier::Visit(PlayerMapType& m)
|
||||||
|
|||||||
@@ -45,16 +45,16 @@ namespace Acore
|
|||||||
Player& i_player;
|
Player& i_player;
|
||||||
std::vector<Unit*>& i_visibleNow;
|
std::vector<Unit*>& i_visibleNow;
|
||||||
bool i_gobjOnly;
|
bool i_gobjOnly;
|
||||||
bool i_largeOnly;
|
|
||||||
UpdateData i_data;
|
UpdateData i_data;
|
||||||
|
|
||||||
VisibleNotifier(Player& player, bool gobjOnly, bool largeOnly) :
|
VisibleNotifier(Player& player, bool gobjOnly) :
|
||||||
i_player(player), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly), i_largeOnly(largeOnly)
|
i_player(player), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly)
|
||||||
{
|
{
|
||||||
i_visibleNow.clear();
|
i_visibleNow.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Visit(GameObjectMapType&);
|
void Visit(GameObjectMapType&);
|
||||||
|
template<class T> void Visit(std::vector<T>& m);
|
||||||
template<class T> void Visit(GridRefMgr<T>& m);
|
template<class T> void Visit(GridRefMgr<T>& m);
|
||||||
void SendToSelf(void);
|
void SendToSelf(void);
|
||||||
};
|
};
|
||||||
@@ -72,8 +72,9 @@ namespace Acore
|
|||||||
|
|
||||||
struct PlayerRelocationNotifier : public VisibleNotifier
|
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); }
|
template<class T> void Visit(GridRefMgr<T>& m) { VisibleNotifier::Visit(m); }
|
||||||
void Visit(PlayerMapType&);
|
void Visit(PlayerMapType&);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,6 +25,13 @@
|
|||||||
#include "WorldPacket.h"
|
#include "WorldPacket.h"
|
||||||
#include "WorldSession.h"
|
#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>
|
template<class T>
|
||||||
inline void Acore::VisibleNotifier::Visit(GridRefMgr<T>& m)
|
inline void Acore::VisibleNotifier::Visit(GridRefMgr<T>& m)
|
||||||
{
|
{
|
||||||
@@ -33,12 +40,7 @@ inline void Acore::VisibleNotifier::Visit(GridRefMgr<T>& m)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
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);
|
i_player.UpdateVisibilityOf(iter->GetSource(), i_data, i_visibleNow);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SEARCHERS & LIST SEARCHERS & WORKERS
|
// SEARCHERS & LIST SEARCHERS & WORKERS
|
||||||
|
|||||||
@@ -118,6 +118,8 @@ void Map::AddToGrid(Creature* obj, Cell const& cell)
|
|||||||
{
|
{
|
||||||
MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY());
|
MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY());
|
||||||
grid->AddGridObject(cell.CellX(), cell.CellY(), obj);
|
grid->AddGridObject(cell.CellX(), cell.CellY(), obj);
|
||||||
|
if (obj->IsFarVisible())
|
||||||
|
grid->AddFarVisibleObject(cell.CellX(), cell.CellY(), obj);
|
||||||
|
|
||||||
obj->SetCurrentCell(cell);
|
obj->SetCurrentCell(cell);
|
||||||
}
|
}
|
||||||
@@ -127,6 +129,8 @@ void Map::AddToGrid(GameObject* obj, Cell const& cell)
|
|||||||
{
|
{
|
||||||
MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY());
|
MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY());
|
||||||
grid->AddGridObject(cell.CellX(), cell.CellY(), obj);
|
grid->AddGridObject(cell.CellX(), cell.CellY(), obj);
|
||||||
|
if (obj->IsFarVisible())
|
||||||
|
grid->AddFarVisibleObject(cell.CellX(), cell.CellY(), obj);
|
||||||
|
|
||||||
obj->SetCurrentCell(cell);
|
obj->SetCurrentCell(cell);
|
||||||
}
|
}
|
||||||
@@ -604,6 +608,52 @@ void Map::RemoveObjectFromMapUpdateList(WorldObject* obj)
|
|||||||
_RemoveObjectFromUpdateList(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()
|
void Map::HandleDelayedVisibility()
|
||||||
{
|
{
|
||||||
if (i_objectsForDelayedVisibility.empty())
|
if (i_objectsForDelayedVisibility.empty())
|
||||||
@@ -656,6 +706,8 @@ void Map::RemoveFromMap(T* obj, bool remove)
|
|||||||
obj->RemoveFromWorld();
|
obj->RemoveFromWorld();
|
||||||
|
|
||||||
obj->RemoveFromGrid();
|
obj->RemoveFromGrid();
|
||||||
|
if (obj->IsFarVisible())
|
||||||
|
RemoveWorldObjectFromFarVisibleMap(obj);
|
||||||
|
|
||||||
obj->ResetMap();
|
obj->ResetMap();
|
||||||
|
|
||||||
@@ -852,6 +904,12 @@ void Map::MoveAllCreaturesInMoveList()
|
|||||||
|
|
||||||
Cell const& old_cell = c->GetCurrentCell();
|
Cell const& old_cell = c->GetCurrentCell();
|
||||||
Cell new_cell(c->GetPositionX(), c->GetPositionY());
|
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();
|
c->RemoveFromGrid();
|
||||||
if (old_cell.DiffGrid(new_cell))
|
if (old_cell.DiffGrid(new_cell))
|
||||||
@@ -881,6 +939,12 @@ void Map::MoveAllGameObjectsInMoveList()
|
|||||||
|
|
||||||
Cell const& old_cell = go->GetCurrentCell();
|
Cell const& old_cell = go->GetCurrentCell();
|
||||||
Cell new_cell(go->GetPositionX(), go->GetPositionY());
|
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();
|
go->RemoveFromGrid();
|
||||||
if (old_cell.DiffGrid(new_cell))
|
if (old_cell.DiffGrid(new_cell))
|
||||||
|
|||||||
@@ -147,6 +147,8 @@ struct ZoneDynamicInfo
|
|||||||
typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
|
typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
|
||||||
typedef std::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap;
|
typedef std::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap;
|
||||||
typedef std::unordered_set<Transport*> TransportsContainer;
|
typedef std::unordered_set<Transport*> TransportsContainer;
|
||||||
|
typedef std::unordered_set<WorldObject*> ZoneWideVisibleWorldObjectsSet;
|
||||||
|
typedef std::unordered_map<uint32 /*ZoneId*/, ZoneWideVisibleWorldObjectsSet> ZoneWideVisibleWorldObjectsMap;
|
||||||
|
|
||||||
enum EncounterCreditType : uint8
|
enum EncounterCreditType : uint8
|
||||||
{
|
{
|
||||||
@@ -496,6 +498,12 @@ public:
|
|||||||
typedef std::vector<WorldObject*> UpdatableObjectList;
|
typedef std::vector<WorldObject*> UpdatableObjectList;
|
||||||
typedef std::unordered_set<WorldObject*> PendingAddUpdatableObjectList;
|
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:
|
private:
|
||||||
|
|
||||||
template<class T> void InitializeObject(T* obj);
|
template<class T> void InitializeObject(T* obj);
|
||||||
@@ -603,6 +611,7 @@ private:
|
|||||||
UpdatableObjectList _updatableObjectList;
|
UpdatableObjectList _updatableObjectList;
|
||||||
PendingAddUpdatableObjectList _pendingAddUpdatableObjectList;
|
PendingAddUpdatableObjectList _pendingAddUpdatableObjectList;
|
||||||
IntervalTimer _updatableObjectListRecheckTimer;
|
IntervalTimer _updatableObjectListRecheckTimer;
|
||||||
|
ZoneWideVisibleWorldObjectsMap _zoneWideVisibleWorldObjectsMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum InstanceResetMethod
|
enum InstanceResetMethod
|
||||||
|
|||||||
@@ -99,7 +99,8 @@ public:
|
|||||||
{ "objectcount", HandleDebugObjectCountCommand, SEC_ADMINISTRATOR, Console::Yes},
|
{ "objectcount", HandleDebugObjectCountCommand, SEC_ADMINISTRATOR, Console::Yes},
|
||||||
{ "dummy", HandleDebugDummyCommand, SEC_ADMINISTRATOR, Console::No },
|
{ "dummy", HandleDebugDummyCommand, SEC_ADMINISTRATOR, Console::No },
|
||||||
{ "mapdata", HandleDebugMapDataCommand, 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 =
|
static ChatCommandTable commandTable =
|
||||||
{
|
{
|
||||||
@@ -1403,6 +1404,36 @@ public:
|
|||||||
|
|
||||||
return true;
|
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()
|
void AddSC_debug_commandscript()
|
||||||
|
|||||||
Reference in New Issue
Block a user