mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-31 09:33:47 +00:00
feat(Core/Visibility): Far visibility worldobjects (#22828)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user