feat(Core/Visibility): Far visibility worldobjects (#22828)

This commit is contained in:
Takenbacon 2025-09-07 04:02:03 -07:00 committed by GitHub
parent d55851c513
commit a28824df85
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 461 additions and 156 deletions

View file

@ -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
{

View file

@ -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

View file

@ -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*/) { }

View file

@ -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;
}

View file

@ -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 (IsPlayer())
{
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;
}

View file

@ -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);

View file

@ -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

View file

@ -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();

View file

@ -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();

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
};

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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;

View file

@ -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)

View file

@ -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&);
};

View file

@ -25,6 +25,13 @@
#include "WorldPacket.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>
inline void Acore::VisibleNotifier::Visit(GridRefMgr<T>& m)
{
@ -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

View file

@ -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))

View file

@ -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

View file

@ -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()