From d18d2b84f2c3e6e1005316625da80c99dd414bcc Mon Sep 17 00:00:00 2001 From: Ovah Date: Tue, 7 Apr 2020 23:28:44 +0200 Subject: Core/Objects: cache current liquid status of objects when updating position data and use it to replace unnecessary vmap lookups (#24399) * dropped unneeded IsUnderwater override for players since the default position data update considers collision height already so we don't have to rely on that tempfix anymore. This actually fixes breathing bars showing up depending on your characters size (gnomes get their breathing bar earlier, taurens later etc) (cherry picked from commit bea850fb73c6c3b3cc4e51bd3a42d178947882a5) --- src/server/game/Entities/Object/Object.cpp | 5 ++-- src/server/game/Entities/Object/Object.h | 3 +++ src/server/game/Entities/Player/Player.cpp | 43 +++++++----------------------- src/server/game/Entities/Player/Player.h | 7 +---- src/server/game/Entities/Unit/Unit.cpp | 31 ++++++++++----------- src/server/game/Entities/Unit/Unit.h | 7 +++-- 6 files changed, 34 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index a530c580be8..ae18e8422d9 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -796,8 +796,8 @@ void MovementInfo::OutDebug() WorldObject::WorldObject(bool isWorldObject) : Object(), WorldLocation(), LastUsedScriptID(0), m_movementInfo(), m_name(), m_isActive(false), m_isFarVisible(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr), -m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_outdoors(false), m_currMap(nullptr), m_InstanceId(0), -_dbPhase(0), m_notifyflags(0) +m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_outdoors(false), m_liquidStatus(LIQUID_MAP_NO_WATER), +m_currMap(nullptr), m_InstanceId(0), _dbPhase(0), m_notifyflags(0) { m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST); m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); @@ -896,6 +896,7 @@ void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& da m_zoneId = area->ParentAreaID; m_outdoors = data.outdoors; m_staticFloorZ = data.floorZ; + m_liquidStatus = data.liquidStatus; } void WorldObject::AddToWorld() diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 0d7e237e937..5af44a47e69 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -63,6 +63,7 @@ class ZoneScript; struct FactionTemplateEntry; struct PositionFullTerrainStatus; struct QuaternionData; +enum ZLiquidStatus : uint32; namespace WorldPackets { @@ -486,6 +487,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation uint32 GetAreaId() const { return m_areaId; } void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const { zoneid = m_zoneId, areaid = m_areaId; } bool IsOutdoors() const { return m_outdoors; } + ZLiquidStatus GetLiquidStatus() const { return m_liquidStatus; } bool IsInWorldPvpZone() const; InstanceScript* GetInstanceScript() const; @@ -733,6 +735,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation uint32 m_areaId; float m_staticFloorZ; bool m_outdoors; + ZLiquidStatus m_liquidStatus; //these functions are used mostly for Relocate() and Corpse/Player specific stuff... //use them ONLY in LoadFromDB()/Create() funcs and nowhere else! diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b6d79ccccb1..baf02061bd4 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -217,7 +217,6 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this) m_MirrorTimerFlags = UNDERWATER_NONE; m_MirrorTimerFlagsLast = UNDERWATER_NONE; - m_isInWater = false; m_hostileReferenceCheckTimer = 0; m_drunkTimer = 0; m_deathTimer = 0; @@ -2084,28 +2083,6 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid, Gameo return go; } -bool Player::IsUnderWater() const -{ - return IsInWater() && - GetPositionZ() < (GetMap()->GetWaterLevel(GetPhaseShift(), GetPositionX(), GetPositionY()) - 2); -} - -void Player::SetInWater(bool inWater) -{ - if (m_isInWater == inWater) - return; - - //define player in water by opcodes - //move player's guid into HateOfflineList of those mobs - //which can't swim and move guid back into ThreatList when - //on surface. - /// @todo exist also swimming mobs, and function must be symmetric to enter/leave water - m_isInWater = inWater; - - // Call base - Unit::SetInWater(inWater); -} - bool Player::IsInAreaTriggerRadius(AreaTriggerEntry const* trigger) const { if (!trigger) @@ -26108,42 +26085,42 @@ int32 Player::NextGroupUpdateSequenceNumber(GroupCategory category) return m_groupUpdateSequences[category].UpdateSequenceNumber++; } -void Player::ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional const& liquidData) +void Player::ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, Optional const& newLiquidData) { // process liquid auras using generic unit code - Unit::ProcessTerrainStatusUpdate(status, liquidData); + Unit::ProcessTerrainStatusUpdate(oldLiquidStatus, newLiquidData); // player specific logic for mirror timers - if (status && liquidData) + if (GetLiquidStatus() && newLiquidData) { // Breath bar state (under water in any liquid type) - if (liquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::AllLiquids)) + if (newLiquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::AllLiquids)) { - if (status & LIQUID_MAP_UNDER_WATER) + if (GetLiquidStatus() & LIQUID_MAP_UNDER_WATER) m_MirrorTimerFlags |= UNDERWATER_INWATER; else m_MirrorTimerFlags &= ~UNDERWATER_INWATER; } // Fatigue bar state (if not on flight path or transport) - if (liquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::DarkWater) && !IsInFlight() && !GetTransport()) + if (newLiquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::DarkWater) && !IsInFlight() && !GetTransport()) m_MirrorTimerFlags |= UNDERWATER_INDARKWATER; else m_MirrorTimerFlags &= ~UNDERWATER_INDARKWATER; // Lava state (any contact) - if (liquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::Magma)) + if (newLiquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::Magma)) { - if (status & MAP_LIQUID_STATUS_IN_CONTACT) + if (GetLiquidStatus() & MAP_LIQUID_STATUS_IN_CONTACT) m_MirrorTimerFlags |= UNDERWATER_INLAVA; else m_MirrorTimerFlags &= ~UNDERWATER_INLAVA; } // Slime state (any contact) - if (liquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::Slime)) + if (newLiquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::Slime)) { - if (status & MAP_LIQUID_STATUS_IN_CONTACT) + if (GetLiquidStatus() & MAP_LIQUID_STATUS_IN_CONTACT) m_MirrorTimerFlags |= UNDERWATER_INSLIME; else m_MirrorTimerFlags &= ~UNDERWATER_INSLIME; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 5c892d33e73..c58e6420e9c 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1124,10 +1124,6 @@ class TC_GAME_API Player : public Unit, public GridObject bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const override; - void SetInWater(bool inWater) override; - - bool IsInWater() const override { return m_isInWater; } - bool IsUnderWater() const override; bool IsInAreaTriggerRadius(AreaTriggerEntry const* trigger) const; void SendInitialPacketsBeforeAddToMap(); @@ -2077,7 +2073,7 @@ class TC_GAME_API Player : public Unit, public GridObject bool UpdatePosition(float x, float y, float z, float orientation, bool teleport = false) override; bool UpdatePosition(Position const& pos, bool teleport = false) override { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); } - void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional const& liquidData) override; + void ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, Optional const& newLiquidData) override; void AtEnterCombat() override; void AtExitCombat() override; @@ -3058,7 +3054,6 @@ class TC_GAME_API Player : public Unit, public GridObject int32 m_MirrorTimer[MAX_TIMERS]; uint8 m_MirrorTimerFlags; uint8 m_MirrorTimerFlagsLast; - bool m_isInWater; // Current teleport data WorldLocation m_teleport_dest; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e10a7f333d5..377fe90c0f3 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -2999,40 +2999,36 @@ bool Unit::isInAccessiblePlaceFor(Creature const* c) const bool Unit::IsInWater() const { - return GetMap()->IsInWater(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ()); + return GetLiquidStatus() & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER); } bool Unit::IsUnderWater() const { - return GetMap()->IsUnderWater(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ()); + return GetLiquidStatus() & LIQUID_MAP_UNDER_WATER; } void Unit::ProcessPositionDataChanged(PositionFullTerrainStatus const& data) { + ZLiquidStatus oldLiquidStatus = GetLiquidStatus(); WorldObject::ProcessPositionDataChanged(data); - ProcessTerrainStatusUpdate(data.liquidStatus, data.liquidInfo); + ProcessTerrainStatusUpdate(oldLiquidStatus, data.liquidInfo); } -void Unit::SetInWater(bool inWater) +void Unit::ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, Optional const& newLiquidData) { + if (!IsControlledByPlayer()) + return; + // remove appropriate auras if we are swimming/not swimming respectively - if (inWater) + if (IsInWater()) RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::UnderWater); else RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::AboveWater); -} - -void Unit::ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional const& liquidData) -{ - if (!IsControlledByPlayer()) - return; - - SetInWater(status & MAP_LIQUID_STATUS_SWIMMING); // liquid aura handling LiquidTypeEntry const* curLiquid = nullptr; - if ((status & MAP_LIQUID_STATUS_SWIMMING) && liquidData) - curLiquid = sLiquidTypeStore.LookupEntry(liquidData->entry); + if (IsInWater() && newLiquidData) + curLiquid = sLiquidTypeStore.LookupEntry(newLiquidData->entry); if (curLiquid != _lastLiquid) { if (_lastLiquid && _lastLiquid->SpellID) @@ -3044,10 +3040,11 @@ void Unit::ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional if (curLiquid && curLiquid->SpellID && (!player || !player->IsGameMaster())) CastSpell(this, curLiquid->SpellID, true); + } - // mount capability depends on liquid state change + // mount capability depends on liquid state change + if (oldLiquidStatus != GetLiquidStatus()) UpdateMountCapability(); - } } void Unit::DeMorph() diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index f85f43731e7..320d62804b9 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1156,8 +1156,8 @@ class TC_GAME_API Unit : public WorldObject bool isTargetableForAttack(bool checkFakeDeath = true) const; - virtual bool IsInWater() const; - virtual bool IsUnderWater() const; + bool IsInWater() const; + bool IsUnderWater() const; bool isInAccessiblePlaceFor(Creature const* c) const; void SendHealSpellLog(HealInfo& healInfo, bool critical = false); @@ -1945,8 +1945,7 @@ class TC_GAME_API Unit : public WorldObject void DisableSpline(); void ProcessPositionDataChanged(PositionFullTerrainStatus const& data) override; - virtual void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional const& liquidData); - virtual void SetInWater(bool inWater); + virtual void ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, Optional const& newLiquidData); // notifiers virtual void AtEnterCombat(); -- cgit v1.2.3