fix(Core/Movement): (#7008)

- Get zone/area IDs from vmap data in the liquid update
- Add new method Map::getFullVMapDataForPosition to get area info and liquid info in a single vmap lookup
- Adjust GetZoneId/GetAreaId on WorldObject to always return these cached fields.
- Clean up liquid state handling on Unit and Player
- Implemented getting area id from gameobject spawns.
- Removed old core related to getting movement flags dependent on environment.
- Movement flags are now processed more precisely and dynamically.

Original source: TrinityCore.

- Closes #5086
- Updates #2208.
This commit is contained in:
UltraNix
2021-08-25 12:41:20 +02:00
committed by GitHub
parent 909c3e5799
commit a8c0a2cc89
47 changed files with 1086 additions and 883 deletions

View File

@@ -950,8 +950,8 @@ WorldObject::WorldObject(bool isWorldObject) : WorldLocation(),
elunaEvents(nullptr),
#endif
LastUsedScriptID(0), m_name(""), m_isActive(false), m_isVisibilityDistanceOverride(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
m_staticFloorZ(INVALID_HEIGHT), m_transport(nullptr), m_currMap(nullptr), m_InstanceId(0),
m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true), m_notifyflags(0), m_executed_notifies(0)
_zoneId(0), _areaId(0), _floorZ(INVALID_HEIGHT), _outdoors(false), _liquidData(), _updatePositionData(false), m_transport(nullptr),
m_currMap(nullptr), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true), m_notifyflags(0), m_executed_notifies(0)
{
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST);
m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
@@ -1040,19 +1040,51 @@ void WorldObject::_Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32
SetPhaseMask(phaseMask, false);
}
uint32 WorldObject::GetZoneId(bool /*forceRecalc*/) const
void WorldObject::SetPositionDataUpdate()
{
return GetBaseMap()->GetZoneId(m_positionX, m_positionY, m_positionZ);
_updatePositionData = true;
// Calls immediately for charmed units
if (GetTypeId() == TYPEID_UNIT && ToUnit()->IsCharmedOwnedByPlayerOrPlayer())
UpdatePositionData();
}
uint32 WorldObject::GetAreaId(bool /*forceRecalc*/) const
void WorldObject::UpdatePositionData()
{
return GetBaseMap()->GetAreaId(m_positionX, m_positionY, m_positionZ);
_updatePositionData = false;
PositionFullTerrainStatus data;
GetMap()->GetFullTerrainStatusForPosition(GetPhaseMask(), GetPositionX(), GetPositionY(), GetPositionZ(), GetCollisionHeight(), data);
ProcessPositionDataChanged(data);
}
void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, bool /*forceRecalc*/) const
void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
{
GetBaseMap()->GetZoneAndAreaId(zoneid, areaid, m_positionX, m_positionY, m_positionZ);
_zoneId = _areaId = data.areaId;
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(_areaId))
if (area->zone)
_zoneId = area->zone;
_outdoors = data.outdoors;
_floorZ = data.floorZ;
_liquidData = data.liquidInfo;
}
void WorldObject::AddToWorld()
{
Object::AddToWorld();
GetMap()->GetZoneAndAreaId(GetPhaseMask(), _zoneId, _areaId, GetPositionX(), GetPositionY(), GetPositionZ());
}
void WorldObject::RemoveFromWorld()
{
if (!IsInWorld())
return;
DestroyForNearbyPlayers();
Object::RemoveFromWorld();
}
InstanceScript* WorldObject::GetInstanceScript()
@@ -1470,7 +1502,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z, float* grou
if (max_z > INVALID_HEIGHT)
{
if (canSwim && unit->GetMap()->IsInWater(x, y, max_z - Z_OFFSET_FIND_HEIGHT))
if (canSwim && unit->GetMap()->IsInWater(unit->GetPhaseMask(), x, y, max_z - Z_OFFSET_FIND_HEIGHT, unit->GetCollisionHeight()))
{
// do not allow creatures to walk on
// water level while swimming
@@ -2137,12 +2169,6 @@ void WorldObject::ResetMap()
//m_InstanceId = 0;
}
Map const* WorldObject::GetBaseMap() const
{
ASSERT(m_currMap);
return m_currMap->GetParent();
}
void WorldObject::AddObjectToRemoveList()
{
ASSERT(m_uint32Values);
@@ -2307,7 +2333,7 @@ void WorldObject::SetZoneScript()
m_zoneScript = (ZoneScript*)map->ToInstanceMap()->GetInstanceScript();
else if (!map->IsBattlegroundOrArena())
{
uint32 zoneId = GetZoneId(true);
uint32 zoneId = GetZoneId();
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(zoneId))
m_zoneScript = bf;
else
@@ -3031,10 +3057,54 @@ float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* gr
float WorldObject::GetFloorZ() const
{
if (!IsInWorld())
return m_staticFloorZ;
if (_updatePositionData)
const_cast<WorldObject*>(this)->UpdatePositionData();
return std::max<float>(m_staticFloorZ, GetMap()->GetGameObjectFloor(GetPhaseMask(), GetPositionX(), GetPositionY(), GetPositionZ() + std::max(GetCollisionHeight(), Z_OFFSET_FIND_HEIGHT)));
if (!IsInWorld())
return _floorZ;
return std::max<float>(_floorZ, GetMap()->GetGameObjectFloor(GetPhaseMask(), GetPositionX(), GetPositionY(), GetPositionZ() + std::max(GetCollisionHeight(), Z_OFFSET_FIND_HEIGHT)));
}
uint32 WorldObject::GetZoneId() const
{
if (_updatePositionData)
const_cast<WorldObject*>(this)->UpdatePositionData();
return _zoneId;
}
uint32 WorldObject::GetAreaId() const
{
if (_updatePositionData)
const_cast<WorldObject*>(this)->UpdatePositionData();
return _areaId;
}
void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const
{
if (_updatePositionData)
const_cast<WorldObject*>(this)->UpdatePositionData();
zoneid = _zoneId;
areaid = _areaId;
}
bool WorldObject::IsOutdoors() const
{
if (_updatePositionData)
const_cast<WorldObject*>(this)->UpdatePositionData();
return _outdoors;
}
LiquidData const& WorldObject::GetLiquidData() const
{
if (_updatePositionData)
const_cast<WorldObject*>(this)->UpdatePositionData();
return _liquidData;
}
void WorldObject::AddAllowedLooter(ObjectGuid guid)

View File

@@ -69,6 +69,8 @@ class Transport;
class StaticTransport;
class MotionTransport;
struct PositionFullTerrainStatus;
typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType;
typedef GuidUnorderedSet UpdatePlayerSet;
@@ -750,15 +752,8 @@ public:
#endif
void _Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32 phaseMask);
void RemoveFromWorld() override
{
if (!IsInWorld())
return;
DestroyForNearbyPlayers();
Object::RemoveFromWorld();
}
void AddToWorld() override;
void RemoveFromWorld() override;
#ifdef ELUNA
ElunaEventProcessor* elunaEvents;
@@ -817,9 +812,11 @@ public:
bool InSamePhase(WorldObject const* obj) const { return InSamePhase(obj->GetPhaseMask()); }
[[nodiscard]] bool InSamePhase(uint32 phasemask) const { return m_useCombinedPhases ? GetPhaseMask() & phasemask : GetPhaseMask() == phasemask; }
[[nodiscard]] virtual uint32 GetZoneId(bool forceRecalc = false) const;
[[nodiscard]] virtual uint32 GetAreaId(bool forceRecalc = false) const;
virtual void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, bool forceRecalc = false) const;
[[nodiscard]] uint32 GetZoneId() const;
[[nodiscard]] uint32 GetAreaId() const;
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const;
[[nodiscard]] bool IsOutdoors() const;
LiquidData const& GetLiquidData() const;
InstanceScript* GetInstanceScript();
@@ -948,9 +945,6 @@ public:
[[nodiscard]] Map* FindMap() const { return m_currMap; }
//used to check all object's GetMap() calls when object is not in world!
//this function should be removed in nearest time...
[[nodiscard]] Map const* GetBaseMap() const;
void SetZoneScript();
void ClearZoneScript();
[[nodiscard]] ZoneScript* GetZoneScript() const { return m_zoneScript; }
@@ -984,6 +978,9 @@ public:
void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& player_set) override;
void GetCreaturesWithEntryInRange(std::list<Creature*>& creatureList, float radius, uint32 entry);
void SetPositionDataUpdate();
void UpdatePositionData();
void AddToObjectUpdate() override;
void RemoveFromObjectUpdate() override;
@@ -1060,7 +1057,13 @@ protected:
const bool m_isWorldObject;
ZoneScript* m_zoneScript;
float m_staticFloorZ;
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const& data);
uint32 _zoneId;
uint32 _areaId;
float _floorZ;
bool _outdoors;
LiquidData _liquidData;
bool _updatePositionData;
// transports
Transport* m_transport;