aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2018-01-28 11:37:20 +0100
committerShauren <shauren.trinity@gmail.com>2018-03-25 19:28:36 +0300
commit91be2332e249147ce3169c46a7da77f0f8c2211d (patch)
treeeab9e0ab76ae523f7a843fe1c2300eba17f53af2 /src
parent1e62b53c66829dc9820117e17bfb44cb2652f814 (diff)
Core/Entities: Phasing rewrite
* Optimized phase visibility checking * Handle all phase flags Closes #16758 Closes #21119
Diffstat (limited to 'src')
-rw-r--r--src/common/Collision/DynamicTree.cpp22
-rw-r--r--src/common/Collision/DynamicTree.h10
-rw-r--r--src/common/Collision/Models/GameObjectModel.cpp4
-rw-r--r--src/common/Collision/Models/GameObjectModel.h6
-rw-r--r--src/common/Utilities/Containers.h37
-rw-r--r--src/common/Utilities/EnumClassFlag.h82
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp18
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp2
-rw-r--r--src/server/game/Chat/Chat.cpp4
-rw-r--r--src/server/game/Chat/Chat.h4
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp58
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp10
-rw-r--r--src/server/game/DataStores/DB2Stores.h3
-rw-r--r--src/server/game/DataStores/DBCEnums.h17
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.cpp3
-rw-r--r--src/server/game/Entities/Conversation/Conversation.cpp3
-rw-r--r--src/server/game/Entities/Corpse/Corpse.cpp7
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp16
-rw-r--r--src/server/game/Entities/Creature/CreatureData.h4
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp14
-rw-r--r--src/server/game/Entities/GameObject/GameObjectData.h5
-rw-r--r--src/server/game/Entities/Object/Object.cpp240
-rw-r--r--src/server/game/Entities/Object/Object.h31
-rw-r--r--src/server/game/Entities/Object/ObjectDefines.h2
-rw-r--r--src/server/game/Entities/Object/PhaseShift.cpp18
-rw-r--r--src/server/game/Entities/Object/PhaseShift.h32
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp3
-rw-r--r--src/server/game/Entities/Player/Player.cpp24
-rw-r--r--src/server/game/Entities/Player/Player.h3
-rw-r--r--src/server/game/Entities/Transport/Transport.cpp22
-rw-r--r--src/server/game/Entities/Transport/Transport.h2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp43
-rw-r--r--src/server/game/Entities/Unit/Unit.h5
-rw-r--r--src/server/game/Garrison/Garrison.cpp3
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp265
-rw-r--r--src/server/game/Globals/ObjectMgr.h70
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp11
-rw-r--r--src/server/game/Handlers/QueryHandler.cpp2
-rw-r--r--src/server/game/Instances/InstanceScript.cpp3
-rw-r--r--src/server/game/Maps/Map.cpp87
-rw-r--r--src/server/game/Maps/Map.h11
-rw-r--r--src/server/game/Maps/TransportMgr.cpp56
-rw-r--r--src/server/game/Maps/TransportMgr.h2
-rw-r--r--src/server/game/Miscellaneous/Language.h16
-rw-r--r--src/server/game/Movement/MotionMaster.cpp4
-rw-r--r--src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp8
-rw-r--r--src/server/game/Phasing/PhaseShift.cpp178
-rw-r--r--src/server/game/Phasing/PhaseShift.h122
-rw-r--r--src/server/game/Phasing/PhasingHandler.cpp545
-rw-r--r--src/server/game/Phasing/PhasingHandler.h72
-rw-r--r--src/server/game/Server/Packets/MiscPackets.cpp48
-rw-r--r--src/server/game/Server/Packets/MiscPackets.h29
-rw-r--r--src/server/game/Server/Packets/PartyPackets.cpp12
-rw-r--r--src/server/game/Server/WorldSession.h2
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp49
-rw-r--r--src/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp15
-rw-r--r--src/server/game/World/World.cpp12
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp27
-rw-r--r--src/server/scripts/Commands/cs_gobject.cpp3
-rw-r--r--src/server/scripts/Commands/cs_group.cpp3
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp35
-rw-r--r--src/server/scripts/Commands/cs_modify.cpp41
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp27
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp8
-rw-r--r--src/server/scripts/Commands/cs_wp.cpp9
-rw-r--r--src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp2
-rw-r--r--src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp2
-rw-r--r--src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp9
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp15
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp8
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp4
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp3
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp27
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp2
-rw-r--r--src/server/scripts/Northrend/zone_borean_tundra.cpp3
-rw-r--r--src/server/scripts/Northrend/zone_sholazar_basin.cpp2
-rw-r--r--src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp3
79 files changed, 1754 insertions, 859 deletions
diff --git a/src/common/Collision/DynamicTree.cpp b/src/common/Collision/DynamicTree.cpp
index 0e6c80d15ca..2fa66ab3adb 100644
--- a/src/common/Collision/DynamicTree.cpp
+++ b/src/common/Collision/DynamicTree.cpp
@@ -146,11 +146,11 @@ void DynamicMapTree::update(uint32 t_diff)
struct DynamicTreeIntersectionCallback
{
- DynamicTreeIntersectionCallback(std::set<uint32> const& phases) : _didHit(false), _phases(phases) { }
+ DynamicTreeIntersectionCallback(PhaseShift const& phaseShift) : _didHit(false), _phaseShift(phaseShift) { }
bool operator()(G3D::Ray const& r, GameObjectModel const& obj, float& distance)
{
- _didHit = obj.intersectRay(r, distance, true, _phases);
+ _didHit = obj.intersectRay(r, distance, true, _phaseShift);
return _didHit;
}
@@ -158,20 +158,20 @@ struct DynamicTreeIntersectionCallback
private:
bool _didHit;
- std::set<uint32> _phases;
+ PhaseShift const& _phaseShift;
};
-bool DynamicMapTree::getIntersectionTime(std::set<uint32> const& phases, G3D::Ray const& ray, G3D::Vector3 const& endPos, float& maxDist) const
+bool DynamicMapTree::getIntersectionTime(G3D::Ray const& ray, G3D::Vector3 const& endPos, PhaseShift const& phaseShift, float& maxDist) const
{
float distance = maxDist;
- DynamicTreeIntersectionCallback callback(phases);
+ DynamicTreeIntersectionCallback callback(phaseShift);
impl->intersectRay(ray, callback, distance, endPos);
if (callback.didHit())
maxDist = distance;
return callback.didHit();
}
-bool DynamicMapTree::getObjectHitPos(std::set<uint32> const& phases, G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, G3D::Vector3& resultHitPos, float modifyDist) const
+bool DynamicMapTree::getObjectHitPos(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, G3D::Vector3& resultHitPos, float modifyDist, PhaseShift const& phaseShift) const
{
bool result = false;
float maxDist = (endPos - startPos).magnitude();
@@ -186,7 +186,7 @@ bool DynamicMapTree::getObjectHitPos(std::set<uint32> const& phases, G3D::Vector
G3D::Vector3 dir = (endPos - startPos)/maxDist; // direction with length of 1
G3D::Ray ray(startPos, dir);
float dist = maxDist;
- if (getIntersectionTime(phases, ray, endPos, dist))
+ if (getIntersectionTime(ray, endPos, phaseShift, dist))
{
resultHitPos = startPos + dir * dist;
if (modifyDist < 0)
@@ -209,7 +209,7 @@ bool DynamicMapTree::getObjectHitPos(std::set<uint32> const& phases, G3D::Vector
return result;
}
-bool DynamicMapTree::isInLineOfSight(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, std::set<uint32> const& phases) const
+bool DynamicMapTree::isInLineOfSight(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, PhaseShift const& phaseShift) const
{
float maxDist = (endPos - startPos).magnitude();
@@ -217,17 +217,17 @@ bool DynamicMapTree::isInLineOfSight(G3D::Vector3 const& startPos, G3D::Vector3
return true;
G3D::Ray r(startPos, (endPos - startPos) / maxDist);
- DynamicTreeIntersectionCallback callback(phases);
+ DynamicTreeIntersectionCallback callback(phaseShift);
impl->intersectRay(r, callback, maxDist, endPos);
return !callback.didHit();
}
-float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist, std::set<uint32> const& phases) const
+float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist, PhaseShift const& phaseShift) const
{
G3D::Vector3 v(x, y, z + 0.5f);
G3D::Ray r(v, G3D::Vector3(0, 0, -1));
- DynamicTreeIntersectionCallback callback(phases);
+ DynamicTreeIntersectionCallback callback(phaseShift);
impl->intersectZAllignedRay(r, callback, maxSearchDist);
if (callback.didHit())
diff --git a/src/common/Collision/DynamicTree.h b/src/common/Collision/DynamicTree.h
index e26ffebdc33..b2a198a1846 100644
--- a/src/common/Collision/DynamicTree.h
+++ b/src/common/Collision/DynamicTree.h
@@ -21,7 +21,6 @@
#define _DYNTREE_H
#include "Define.h"
-#include <set>
namespace G3D
{
@@ -30,6 +29,7 @@ namespace G3D
}
class GameObjectModel;
+class PhaseShift;
struct DynTreeImpl;
class TC_COMMON_API DynamicMapTree
@@ -41,11 +41,11 @@ public:
DynamicMapTree();
~DynamicMapTree();
- bool isInLineOfSight(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, std::set<uint32> const& phases) const;
- bool getIntersectionTime(std::set<uint32> const& phases, G3D::Ray const& ray, G3D::Vector3 const& endPos, float& maxDist) const;
- bool getObjectHitPos(std::set<uint32> const& phases, G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, G3D::Vector3& resultHitPos, float modifyDist) const;
+ bool isInLineOfSight(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, PhaseShift const& phaseShift) const;
+ bool getIntersectionTime(G3D::Ray const& ray, G3D::Vector3 const& endPos, PhaseShift const& phaseShift, float& maxDist) const;
+ bool getObjectHitPos(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, G3D::Vector3& resultHitPos, float modifyDist, PhaseShift const& phaseShift) const;
- float getHeight(float x, float y, float z, float maxSearchDist, std::set<uint32> const& phases) const;
+ float getHeight(float x, float y, float z, float maxSearchDist, PhaseShift const& phaseShift) const;
void insert(const GameObjectModel&);
void remove(const GameObjectModel&);
diff --git a/src/common/Collision/Models/GameObjectModel.cpp b/src/common/Collision/Models/GameObjectModel.cpp
index 538086f2ea3..350c52bfde0 100644
--- a/src/common/Collision/Models/GameObjectModel.cpp
+++ b/src/common/Collision/Models/GameObjectModel.cpp
@@ -152,12 +152,12 @@ GameObjectModel* GameObjectModel::Create(std::unique_ptr<GameObjectModelOwnerBas
return mdl;
}
-bool GameObjectModel::intersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, std::set<uint32> const& phases) const
+bool GameObjectModel::intersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, PhaseShift const& phaseShift) const
{
if (!isCollisionEnabled() || !owner->IsSpawned())
return false;
- if (!owner->IsInPhase(phases))
+ if (!owner->IsInPhase(phaseShift))
return false;
float time = ray.intersectionTime(iBound);
diff --git a/src/common/Collision/Models/GameObjectModel.h b/src/common/Collision/Models/GameObjectModel.h
index 1e42da90d85..53d1d1ca149 100644
--- a/src/common/Collision/Models/GameObjectModel.h
+++ b/src/common/Collision/Models/GameObjectModel.h
@@ -26,7 +26,6 @@
#include "Define.h"
#include <memory>
-#include <set>
namespace VMAP
{
@@ -34,6 +33,7 @@ namespace VMAP
}
class GameObject;
+class PhaseShift;
struct GameObjectDisplayInfoEntry;
class TC_COMMON_API GameObjectModelOwnerBase
@@ -43,7 +43,7 @@ public:
virtual bool IsSpawned() const { return false; }
virtual uint32 GetDisplayId() const { return 0; }
- virtual bool IsInPhase(std::set<uint32> const& /*phases*/) const { return false; }
+ virtual bool IsInPhase(PhaseShift const& /*phaseShift*/) const { return false; }
virtual G3D::Vector3 GetPosition() const { return G3D::Vector3::zero(); }
virtual float GetOrientation() const { return 0.0f; }
virtual float GetScale() const { return 1.0f; }
@@ -66,7 +66,7 @@ public:
void enableCollision(bool enable) { _collisionEnabled = enable; }
bool isCollisionEnabled() const { return _collisionEnabled; }
- bool intersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, std::set<uint32> const& phases) const;
+ bool intersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, PhaseShift const& phaseShift) const;
static GameObjectModel* Create(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath);
diff --git a/src/common/Utilities/Containers.h b/src/common/Utilities/Containers.h
index cf23949c10a..581fbfabe6b 100644
--- a/src/common/Utilities/Containers.h
+++ b/src/common/Utilities/Containers.h
@@ -118,7 +118,7 @@ namespace Trinity
* Note: container cannot be empty
*/
template<class C, class Fn>
- auto SelectRandomWeightedContainerElement(C const& container, Fn weightExtractor) -> decltype(std::begin(container))
+ inline auto SelectRandomWeightedContainerElement(C const& container, Fn weightExtractor) -> decltype(std::begin(container))
{
std::vector<double> weights;
weights.reserve(Size(container));
@@ -161,7 +161,7 @@ namespace Trinity
* @return true if containers have a common element, false otherwise.
*/
template<class Iterator1, class Iterator2>
- bool Intersects(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
+ inline bool Intersects(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
{
while (first1 != last1 && first2 != last2)
{
@@ -177,6 +177,37 @@ namespace Trinity
}
/**
+ * @fn bool Trinity::Containers::Intersects(Iterator first1, Iterator last1, Iterator first2, Iterator last2, Predicate&& equalPred)
+ *
+ * @brief Checks if two SORTED containers have a common element
+ *
+ * @param first1 Iterator pointing to start of the first container
+ * @param last1 Iterator pointing to end of the first container
+ * @param first2 Iterator pointing to start of the second container
+ * @param last2 Iterator pointing to end of the second container
+ * @param equalPred Additional predicate to exclude elements
+ *
+ * @return true if containers have a common element, false otherwise.
+ */
+ template<class Iterator1, class Iterator2, class Predicate>
+ inline bool Intersects(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2, Predicate&& equalPred)
+ {
+ while (first1 != last1 && first2 != last2)
+ {
+ if (*first1 < *first2)
+ ++first1;
+ else if (*first2 < *first1)
+ ++first2;
+ else if (!equalPred(*first1, *first2))
+ ++first1, ++first2;
+ else
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
* Returns a pointer to mapped value (or the value itself if map stores pointers)
*/
template<class M>
@@ -187,7 +218,7 @@ namespace Trinity
}
template<class K, class V, template<class, class, class...> class M, class... Rest>
- void MultimapErasePair(M<K, V, Rest...>& multimap, K const& key, V const& value)
+ inline void MultimapErasePair(M<K, V, Rest...>& multimap, K const& key, V const& value)
{
auto range = multimap.equal_range(key);
for (auto itr = range.first; itr != range.second;)
diff --git a/src/common/Utilities/EnumClassFlag.h b/src/common/Utilities/EnumClassFlag.h
new file mode 100644
index 00000000000..68ee56edb07
--- /dev/null
+++ b/src/common/Utilities/EnumClassFlag.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EnumClassFlag_h__
+#define EnumClassFlag_h__
+
+#include <type_traits>
+
+template<typename T>
+class EnumClassFlag
+{
+ static_assert(std::is_enum<T>::value, "EnumClassFlag must be used only with enums");
+
+public:
+ /*implicit*/ EnumClassFlag(T value) : _value(value) { }
+
+ EnumClassFlag& operator&=(EnumClassFlag right)
+ {
+ _value = static_cast<T>(static_cast<std::underlying_type_t<T>>(_value) & static_cast<std::underlying_type_t<T>>(right._value));
+ return *this;
+ }
+
+ friend EnumClassFlag operator&(EnumClassFlag left, EnumClassFlag right)
+ {
+ return left &= right;
+ }
+
+ EnumClassFlag operator|=(EnumClassFlag right)
+ {
+ _value = static_cast<T>(static_cast<std::underlying_type_t<T>>(_value) | static_cast<std::underlying_type_t<T>>(right._value));
+ return *this;
+ }
+
+ friend EnumClassFlag operator|(EnumClassFlag left, EnumClassFlag right)
+ {
+ return left |= right;
+ }
+
+ EnumClassFlag operator~() const
+ {
+ return static_cast<T>(~static_cast<std::underlying_type_t<T>>(_value));
+ }
+
+ void RemoveFlag(EnumClassFlag flag)
+ {
+ _value = static_cast<T>(static_cast<std::underlying_type_t<T>>(_value) & ~static_cast<std::underlying_type_t<T>>(flag._value));
+ }
+
+ bool HasFlag(T flag) const
+ {
+ return (static_cast<std::underlying_type_t<T>>(_value) & static_cast<std::underlying_type_t<T>>(flag)) != 0;
+ }
+
+ operator T() const
+ {
+ return _value;
+ }
+
+ std::underlying_type_t<T> AsUnderlyingType() const
+ {
+ return static_cast<std::underlying_type_t<T>>(_value);
+ }
+
+private:
+ T _value;
+};
+
+#endif // EnumClassFlag_h__
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 48a74a3cd79..83e5d00ec63 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -34,6 +34,7 @@
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "Random.h"
#include "SmartAI.h"
#include "SpellAuras.h"
@@ -1246,7 +1247,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
- (*itr)->SetInPhase(e.action.ingamePhaseId.id, true, e.action.ingamePhaseId.apply == 1);
+ {
+ if (e.action.ingamePhaseId.apply == 1)
+ PhasingHandler::AddPhase(*itr, e.action.ingamePhaseId.id, true);
+ else
+ PhasingHandler::RemovePhase(*itr, e.action.ingamePhaseId.id, true);
+ }
delete targets;
break;
@@ -1258,11 +1264,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (!targets)
break;
- std::set<uint32> phases = sDB2Manager.GetPhasesForGroup(e.action.ingamePhaseGroup.groupId);
-
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
- for (auto phase : phases)
- (*itr)->SetInPhase(phase, true, e.action.ingamePhaseGroup.apply == 1);
+ {
+ if (e.action.ingamePhaseGroup.apply == 1)
+ PhasingHandler::AddPhaseGroup(*itr, e.action.ingamePhaseGroup.groupId, true);
+ else
+ PhasingHandler::RemovePhaseGroup(*itr, e.action.ingamePhaseGroup.groupId, true);
+ }
delete targets;
break;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index a2096248851..f6d0ad7b443 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -1374,7 +1374,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
}
- if (sDB2Manager.GetPhasesForGroup(phaseGroup).empty())
+ if (!sDB2Manager.GetPhasesForGroup(phaseGroup))
{
TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid phase group id %u for creature " SI64FMTD ", skipped", phaseGroup, e.entryOrGuid);
return false;
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
index e7aacf6c159..8ef212e6d85 100644
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -1097,7 +1097,7 @@ LocaleConstant ChatHandler::GetSessionDbcLocale() const
return m_session->GetSessionDbcLocale();
}
-int ChatHandler::GetSessionDbLocaleIndex() const
+LocaleConstant ChatHandler::GetSessionDbLocaleIndex() const
{
return m_session->GetSessionDbLocaleIndex();
}
@@ -1183,7 +1183,7 @@ LocaleConstant CliHandler::GetSessionDbcLocale() const
return sWorld->GetDefaultDbcLocale();
}
-int CliHandler::GetSessionDbLocaleIndex() const
+LocaleConstant CliHandler::GetSessionDbLocaleIndex() const
{
return sObjectMgr->GetDBCLocaleIndex();
}
diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h
index f7c27bfd90d..9e4b6e35702 100644
--- a/src/server/game/Chat/Chat.h
+++ b/src/server/game/Chat/Chat.h
@@ -101,7 +101,7 @@ class TC_GAME_API ChatHandler
virtual std::string GetNameLink() const;
virtual bool needReportToTarget(Player* chr) const;
virtual LocaleConstant GetSessionDbcLocale() const;
- virtual int GetSessionDbLocaleIndex() const;
+ virtual LocaleConstant GetSessionDbLocaleIndex() const;
bool HasLowerSecurity(Player* target, ObjectGuid guid, bool strong = false);
bool HasLowerSecurityAccount(WorldSession* target, uint32 account, bool strong = false);
@@ -166,7 +166,7 @@ class TC_GAME_API CliHandler : public ChatHandler
std::string GetNameLink() const override;
bool needReportToTarget(Player* chr) const override;
LocaleConstant GetSessionDbcLocale() const override;
- int GetSessionDbLocaleIndex() const override;
+ LocaleConstant GetSessionDbLocaleIndex() const override;
private:
void* m_callbackArg;
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index 8598b44915d..50726b91cad 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -30,6 +30,7 @@
#include "LootMgr.h"
#include "Map.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "Pet.h"
#include "ReputationMgr.h"
@@ -413,7 +414,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
}
case CONDITION_PHASEID:
{
- condMeets = object->IsInPhase(ConditionValue1);
+ condMeets = object->GetPhaseShift().HasPhase(ConditionValue1);
break;
}
case CONDITION_TITLE:
@@ -454,7 +455,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
}
case CONDITION_TERRAIN_SWAP:
{
- condMeets = object->IsInTerrainSwap(ConditionValue1);
+ condMeets = object->GetPhaseShift().HasVisibleMapId(ConditionValue1);
break;
}
case CONDITION_STAND_STATE:
@@ -1066,17 +1067,7 @@ void ConditionMgr::LoadConditions(bool isReload)
sSpellMgr->UnloadSpellInfoImplicitTargetConditionLists();
- TC_LOG_INFO("misc", "Re-Loading `terrain_phase_info` Table for Conditions!");
- sObjectMgr->LoadTerrainPhaseInfo();
-
- TC_LOG_INFO("misc", "Re-Loading `terrain_swap_defaults` Table for Conditions!");
- sObjectMgr->LoadTerrainSwapDefaults();
-
- TC_LOG_INFO("misc", "Re-Loading `terrain_worldmap` Table for Conditions!");
- sObjectMgr->LoadTerrainWorldMaps();
-
- TC_LOG_INFO("misc", "Re-Loading `phase_area` Table for Conditions!");
- sObjectMgr->LoadAreaPhases();
+ sObjectMgr->UnloadPhaseConditions();
}
QueryResult result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, "
@@ -1464,28 +1455,33 @@ bool ConditionMgr::addToPhases(Condition* cond) const
{
if (!cond->SourceEntry)
{
- bool found = false;
- PhaseInfo& p = sObjectMgr->GetAreaAndZonePhasesForLoading();
- for (auto phaseItr = p.begin(); phaseItr != p.end(); ++phaseItr)
+ if (PhaseInfoStruct const* phaseInfo = sObjectMgr->GetPhaseInfo(cond->SourceGroup))
{
- for (PhaseInfoStruct& phase : phaseItr->second)
+ bool found = false;
+ for (uint32 areaId : phaseInfo->Areas)
{
- if (phase.Id == cond->SourceGroup)
+ if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(areaId)))
{
- phase.Conditions.push_back(cond);
- found = true;
+ for (PhaseAreaInfo& phase : *phases)
+ {
+ if (phase.PhaseInfo->Id == cond->SourceGroup)
+ {
+ phase.Conditions.push_back(cond);
+ found = true;
+ }
+ }
}
}
- }
- if (found)
- return true;
+ if (found)
+ return true;
+ }
}
- else if (std::vector<PhaseInfoStruct>* phases = sObjectMgr->GetPhasesForAreaOrZoneForLoading(cond->SourceEntry))
+ else if (std::vector<PhaseAreaInfo>* phases = const_cast<std::vector<PhaseAreaInfo>*>(sObjectMgr->GetPhasesForArea(cond->SourceEntry)))
{
- for (PhaseInfoStruct& phase : *phases)
+ for (PhaseAreaInfo& phase : *phases)
{
- if (phase.Id == cond->SourceGroup)
+ if (phase.PhaseInfo->Id == cond->SourceGroup)
{
phase.Conditions.push_back(cond);
return true;
@@ -2809,15 +2805,9 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio
|| condition->MinExpansionLevel > int32(sWorld->getIntConfig(CONFIG_EXPANSION))))
return false;
- if (condition->PhaseID && !player->IsInPhase(condition->PhaseID))
- return false;
-
- if (condition->PhaseGroupID)
- {
- std::set<uint32> phases = sDB2Manager.GetPhasesForGroup(condition->PhaseGroupID);
- if (!Trinity::Containers::Intersects(phases.begin(), phases.end(), player->GetPhases().begin(), player->GetPhases().end()))
+ if (condition->PhaseID || condition->PhaseGroupID || condition->PhaseUseFlags)
+ if (!PhasingHandler::InDbPhaseShift(player, condition->PhaseUseFlags, condition->PhaseID, condition->PhaseGroupID))
return false;
- }
if (condition->QuestKillID)
{
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index dd3d58b1340..486b9356ecd 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -309,7 +309,7 @@ typedef std::unordered_map<uint32, DB2Manager::MountTypeXCapabilitySet> MountCap
typedef std::unordered_map<uint32, DB2Manager::MountXDisplayContainer> MountDisplaysCointainer;
typedef std::unordered_map<uint32, std::array<std::vector<NameGenEntry const*>, 2>> NameGenContainer;
typedef std::array<std::vector<Trinity::wregex>, TOTAL_LOCALES + 1> NameValidationRegexContainer;
-typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer;
+typedef std::unordered_map<uint32, std::vector<uint32>> PhaseGroupContainer;
typedef std::array<PowerTypeEntry const*, MAX_POWERS> PowerTypesContainer;
typedef std::vector<PvpTalentEntry const*> PvpTalentsByPosition[MAX_CLASSES][MAX_PVP_TALENT_TIERS][MAX_PVP_TALENT_COLUMNS];
typedef std::unordered_map<uint32, std::pair<std::vector<QuestPackageItemEntry const*>, std::vector<QuestPackageItemEntry const*>>> QuestPackageItemContainer;
@@ -935,7 +935,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
for (PhaseXPhaseGroupEntry const* group : sPhaseXPhaseGroupStore)
if (PhaseEntry const* phase = sPhaseStore.LookupEntry(group->PhaseID))
- _phasesByGroup[group->PhaseGroupID].insert(phase->ID);
+ _phasesByGroup[group->PhaseGroupID].push_back(phase->ID);
for (PowerTypeEntry const* powerType : sPowerTypeStore)
{
@@ -1963,13 +1963,13 @@ uint32 DB2Manager::GetQuestUniqueBitFlag(uint32 questId)
return v2->UniqueBitFlag;
}
-std::set<uint32> DB2Manager::GetPhasesForGroup(uint32 group) const
+std::vector<uint32> const* DB2Manager::GetPhasesForGroup(uint32 group) const
{
auto itr = _phasesByGroup.find(group);
if (itr != _phasesByGroup.end())
- return itr->second;
+ return &itr->second;
- return std::set<uint32>();
+ return nullptr;
}
PowerTypeEntry const* DB2Manager::GetPowerTypeEntry(Powers power) const
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index 886ab57822f..f923d6c437b 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -206,6 +206,7 @@ TC_GAME_API extern DB2Storage<UnitPowerBarEntry> sUnitPowerBa
TC_GAME_API extern DB2Storage<VehicleEntry> sVehicleStore;
TC_GAME_API extern DB2Storage<VehicleSeatEntry> sVehicleSeatStore;
TC_GAME_API extern DB2Storage<WorldEffectEntry> sWorldEffectStore;
+TC_GAME_API extern DB2Storage<WorldMapAreaEntry> sWorldMapAreaStore;
TC_GAME_API extern DB2Storage<WorldMapOverlayEntry> sWorldMapOverlayStore;
TC_GAME_API extern DB2Storage<WorldSafeLocsEntry> sWorldSafeLocsStore;
@@ -302,7 +303,7 @@ public:
MountTypeXCapabilitySet const* GetMountCapabilities(uint32 mountType) const;
MountXDisplayContainer const* GetMountDisplays(uint32 mountId) const;
ResponseCodes ValidateName(std::wstring const& name, LocaleConstant locale) const;
- std::set<uint32> GetPhasesForGroup(uint32 group) const;
+ std::vector<uint32> const* GetPhasesForGroup(uint32 group) const;
PowerTypeEntry const* GetPowerTypeEntry(Powers power) const;
PowerTypeEntry const* GetPowerTypeByName(std::string const& name) const;
uint8 GetPvpItemLevelBonus(uint32 itemId) const;
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 5ea1ff3d2a8..404c5de75a8 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -814,6 +814,23 @@ enum MountFlags
MOUNT_FLAG_HIDE_IF_UNKNOWN = 0x40
};
+enum PhaseEntryFlags : uint16
+{
+ PHASE_FLAG_NORMAL = 0x08,
+ PHASE_FLAG_COSMETIC = 0x10,
+ PHASE_FLAG_PERSONAL = 0x20
+};
+
+// PhaseUseFlags fields in different db2s
+enum PhaseUseFlagsValues : uint8
+{
+ PHASE_USE_FLAGS_NONE = 0x0,
+ PHASE_USE_FLAGS_ALWAYS_VISIBLE = 0x1,
+ PHASE_USE_FLAGS_INVERSE = 0x2,
+
+ PHASE_USE_FLAGS_ALL = PHASE_USE_FLAGS_ALWAYS_VISIBLE | PHASE_USE_FLAGS_INVERSE
+};
+
enum PrestigeLevelInfoFlags : uint8
{
PRESTIGE_FLAG_DISABLED = 0x01 // Prestige levels with this flag won't be included to calculate max prestigelevel.
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
index 671ca840102..6c36fec788f 100644
--- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
+++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
@@ -28,6 +28,7 @@
#include "Log.h"
#include "Object.h"
#include "ObjectAccessor.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "SpellInfo.h"
@@ -127,7 +128,7 @@ bool AreaTrigger::Create(uint32 spellMiscId, Unit* caster, Unit* target, SpellIn
if (GetMiscTemplate()->ScaleInfo.ExtraScale[scaleCurveIndex].AsInt32)
SetUInt32Value(AREATRIGGER_EXTRA_SCALE_CURVE + scaleCurveIndex, GetMiscTemplate()->ScaleInfo.ExtraScale[scaleCurveIndex].AsInt32);
- CopyPhaseFrom(caster);
+ PhasingHandler::InheritPhaseShift(this, caster);
if (target && GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_ATTACHED))
{
diff --git a/src/server/game/Entities/Conversation/Conversation.cpp b/src/server/game/Entities/Conversation/Conversation.cpp
index 1d7d5a6cfae..13339f3169f 100644
--- a/src/server/game/Entities/Conversation/Conversation.cpp
+++ b/src/server/game/Entities/Conversation/Conversation.cpp
@@ -20,6 +20,7 @@
#include "IteratorPair.h"
#include "Log.h"
#include "Map.h"
+#include "PhasingHandler.h"
#include "ScriptMgr.h"
#include "Unit.h"
#include "UpdateData.h"
@@ -115,7 +116,7 @@ bool Conversation::Create(ObjectGuid::LowType lowGuid, uint32 conversationEntry,
Relocate(pos);
Object::_Create(ObjectGuid::Create<HighGuid::Conversation>(GetMapId(), conversationEntry, lowGuid));
- CopyPhaseFrom(creator);
+ PhasingHandler::InheritPhaseShift(this, creator);
SetEntry(conversationEntry);
SetObjectScale(1.0f);
diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp
index 436032b89fe..a62b2ecbbc1 100644
--- a/src/server/game/Entities/Corpse/Corpse.cpp
+++ b/src/server/game/Entities/Corpse/Corpse.cpp
@@ -23,6 +23,7 @@
#include "Log.h"
#include "Map.h"
#include "ObjectAccessor.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "UpdateData.h"
#include "World.h"
@@ -89,7 +90,7 @@ bool Corpse::Create(ObjectGuid::LowType guidlow, Player* owner)
_cellCoord = Trinity::ComputeCellCoord(GetPositionX(), GetPositionY());
- CopyPhaseFrom(owner);
+ PhasingHandler::InheritPhaseShift(this, owner);
return true;
}
@@ -119,12 +120,12 @@ void Corpse::SaveToDB()
stmt->setUInt32(index++, GetInstanceId()); // instanceId
trans->Append(stmt);
- for (uint32 phaseId : GetPhases())
+ for (PhaseShift::PhaseRef const& phase : GetPhaseShift().GetPhases())
{
index = 0;
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CORPSE_PHASES);
stmt->setUInt64(index++, GetOwnerGUID().GetCounter()); // OwnerGuid
- stmt->setUInt32(index++, phaseId); // PhaseId
+ stmt->setUInt32(index++, phase.Id); // PhaseId
trans->Append(stmt);
}
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 6b28aae6562..9881945a825 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -38,6 +38,7 @@
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "PoolMgr.h"
#include "QuestDef.h"
@@ -861,12 +862,11 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 entry, float
ASSERT(map);
SetMap(map);
- if (data && data->phaseId)
- SetInPhase(data->phaseId, false, true);
-
- if (data && data->phaseGroup)
- for (auto ph : sDB2Manager.GetPhasesForGroup(data->phaseGroup))
- SetInPhase(ph, false, true);
+ if (data)
+ {
+ PhasingHandler::InitDbPhaseShift(GetPhaseShift(), data->phaseUseFlags, data->phaseId, data->phaseGroup);
+ PhasingHandler::InitDbVisibleMapId(GetPhaseShift(), data->terrainSwapMap);
+ }
CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry);
if (!cinfo)
@@ -1471,7 +1471,7 @@ bool Creature::LoadCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool ad
m_deathState = DEAD;
if (CanFly())
{
- float tz = map->GetHeight(GetPhases(), data->posX, data->posY, data->posZ, true, MAX_FALL_DISTANCE);
+ float tz = map->GetHeight(GetPhaseShift(), data->posX, data->posY, data->posZ, true, MAX_FALL_DISTANCE);
if (data->posZ - tz > 0.1f && Trinity::IsValidMapCoord(tz))
Relocate(data->posX, data->posY, tz);
}
@@ -2809,7 +2809,7 @@ void Creature::UpdateMovementFlags()
return;
// Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
- float ground = GetMap()->GetHeight(GetPhases(), GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
+ float ground = GetMap()->GetHeight(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
bool isInAir = (G3D::fuzzyGt(GetPositionZMinusOffset(), ground + 0.05f) || G3D::fuzzyLt(GetPositionZMinusOffset(), ground - 0.05f)); // Can be underground too, prevent the falling
diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h
index b933f6cb399..fddbc672542 100644
--- a/src/server/game/Entities/Creature/CreatureData.h
+++ b/src/server/game/Entities/Creature/CreatureData.h
@@ -500,7 +500,7 @@ struct CreatureData
posX(0.0f), posY(0.0f), posZ(0.0f), orientation(0.0f), spawntimesecs(0),
spawndist(0.0f), currentwaypoint(0), curhealth(0), curmana(0), movementType(0),
spawnMask(0), npcflag(0), unit_flags(0), unit_flags2(0), unit_flags3(0), dynamicflags(0),
- phaseId(0), phaseGroup(0), ScriptId(0), dbData(true) { }
+ phaseUseFlags(0), phaseId(0), phaseGroup(0), terrainSwapMap(-1), ScriptId(0), dbData(true) { }
uint32 id; // entry in creature_template
uint16 mapid;
uint32 displayid;
@@ -521,8 +521,10 @@ struct CreatureData
uint32 unit_flags2; // enum UnitFlags2 mask values
uint32 unit_flags3; // enum UnitFlags3 mask values
uint32 dynamicflags;
+ uint8 phaseUseFlags;
uint32 phaseId;
uint32 phaseGroup;
+ int32 terrainSwapMap;
uint32 ScriptId;
bool dbData;
};
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 26d70dcb2a1..f4c2c9fbe40 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -35,6 +35,7 @@
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "OutdoorPvPMgr.h"
+#include "PhasingHandler.h"
#include "PoolMgr.h"
#include "ScriptMgr.h"
#include "SpellMgr.h"
@@ -988,15 +989,8 @@ bool GameObject::LoadGameObjectFromDB(ObjectGuid::LowType spawnId, Map* map, boo
if (!Create(entry, map, pos, data->rotation, animprogress, go_state, artKit))
return false;
- if (data->phaseId)
- SetInPhase(data->phaseId, false, true);
-
- if (data->phaseGroup)
- {
- // Set the gameobject in all the phases of the phasegroup
- for (auto ph : sDB2Manager.GetPhasesForGroup(data->phaseGroup))
- SetInPhase(ph, false, true);
- }
+ PhasingHandler::InitDbPhaseShift(GetPhaseShift(), data->phaseUseFlags, data->phaseId, data->phaseGroup);
+ PhasingHandler::InitDbVisibleMapId(GetPhaseShift(), data->terrainSwapMap);
if (data->spawntimesecs >= 0)
{
@@ -2623,7 +2617,7 @@ public:
virtual bool IsSpawned() const override { return _owner->isSpawned(); }
virtual uint32 GetDisplayId() const override { return _owner->GetDisplayId(); }
- virtual bool IsInPhase(std::set<uint32> const& phases) const override { return _owner->IsInPhase(phases); }
+ virtual bool IsInPhase(PhaseShift const& phaseShift) const override { return _owner->GetPhaseShift().CanSee(phaseShift); }
virtual G3D::Vector3 GetPosition() const override { return G3D::Vector3(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()); }
virtual float GetOrientation() const override { return _owner->GetOrientation(); }
virtual float GetScale() const override { return _owner->GetObjectScale(); }
diff --git a/src/server/game/Entities/GameObject/GameObjectData.h b/src/server/game/Entities/GameObject/GameObjectData.h
index 5dddb33aeee..7491a3d8ac9 100644
--- a/src/server/game/Entities/GameObject/GameObjectData.h
+++ b/src/server/game/Entities/GameObject/GameObjectData.h
@@ -855,7 +855,8 @@ struct GameObjectAddon
struct GameObjectData
{
explicit GameObjectData() : id(0), mapid(0), posX(0.0f), posY(0.0f), posZ(0.0f), orientation(0.0f), spawntimesecs(0),
- animprogress(0), go_state(GO_STATE_ACTIVE), spawnMask(0), artKit(0), phaseId(0), phaseGroup(0), ScriptId(0), dbData(true) { }
+ animprogress(0), go_state(GO_STATE_ACTIVE), spawnMask(0), artKit(0),
+ phaseUseFlags(0), phaseId(0), phaseGroup(0), terrainSwapMap(-1), ScriptId(0), dbData(true) { }
uint32 id; // entry in gamobject_template
uint16 mapid;
float posX;
@@ -868,8 +869,10 @@ struct GameObjectData
GOState go_state;
uint64 spawnMask;
uint8 artKit;
+ uint8 phaseUseFlags;
uint32 phaseId;
uint32 phaseGroup;
+ int32 terrainSwapMap;
uint32 ScriptId;
bool dbData;
};
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 05f7a37abb0..1ec8586c90f 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -33,6 +33,7 @@
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "OutdoorPvPMgr.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "SharedDefines.h"
#include "SpellAuraEffects.h"
@@ -1780,7 +1781,7 @@ bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
else
GetHitSpherePointFor({ ox, oy, oz }, x, y, z);
- return GetMap()->isInLineOfSight(x, y, z + 2.0f, ox, oy, oz + 2.0f, GetPhases());
+ return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z + 2.0f, ox, oy, oz + 2.0f);
}
return true;
@@ -1950,7 +1951,7 @@ Position WorldObject::GetRandomPoint(const Position &srcPos, float distance) con
void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const
{
- float new_z = GetMap()->GetHeight(GetPhases(), x, y, z + 2.0f, true);
+ float new_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z + 2.0f, true);
if (new_z > INVALID_HEIGHT)
z = new_z + 0.05f; // just to be sure that we are not a few pixel under the surface
}
@@ -1972,8 +1973,8 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
bool canSwim = ToCreature()->CanSwim();
float ground_z = z;
float max_z = canSwim
- ? GetMap()->GetWaterOrGroundLevel(GetPhases(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK))
- : ((ground_z = GetMap()->GetHeight(GetPhases(), x, y, z, true)));
+ ? GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK))
+ : ((ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true)));
if (max_z > INVALID_HEIGHT)
{
if (z > max_z)
@@ -1984,7 +1985,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
}
else
{
- float ground_z = GetMap()->GetHeight(GetPhases(), x, y, z, true);
+ float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true);
if (z < ground_z)
z = ground_z;
}
@@ -1996,7 +1997,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
if (!ToPlayer()->CanFly())
{
float ground_z = z;
- float max_z = GetMap()->GetWaterOrGroundLevel(GetPhases(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK));
+ float max_z = GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK));
if (max_z > INVALID_HEIGHT)
{
if (z > max_z)
@@ -2007,7 +2008,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
}
else
{
- float ground_z = GetMap()->GetHeight(GetPhases(), x, y, z, true);
+ float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true);
if (z < ground_z)
z = ground_z;
}
@@ -2015,7 +2016,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const
}
default:
{
- float ground_z = GetMap()->GetHeight(GetPhases(), x, y, z, true);
+ float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true);
if (ground_z > INVALID_HEIGHT)
z = ground_z;
break;
@@ -2428,7 +2429,8 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert
}
// Set the summon to the summoner's phase
- summon->CopyPhaseFrom(summoner);
+ if (summoner)
+ PhasingHandler::InheritPhaseShift(summon, summoner);
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId);
@@ -2533,7 +2535,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, Position const& pos, Qua
if (!go)
return nullptr;
- go->CopyPhaseFrom(this);
+ PhasingHandler::InheritPhaseShift(go, this);
go->SetRespawnTime(respawnTime);
if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT) //not sure how to handle this
@@ -2748,8 +2750,8 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle)
return;
}
- ground = GetMap()->GetHeight(GetPhases(), destx, desty, MAX_HEIGHT, true);
- floor = GetMap()->GetHeight(GetPhases(), destx, desty, pos.m_positionZ, true);
+ ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true);
+ floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true);
destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor;
float step = dist/10.0f;
@@ -2761,8 +2763,8 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle)
{
destx -= step * std::cos(angle);
desty -= step * std::sin(angle);
- ground = GetMap()->GetHeight(GetPhases(), destx, desty, MAX_HEIGHT, true);
- floor = GetMap()->GetHeight(GetPhases(), destx, desty, pos.m_positionZ, true);
+ ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true);
+ floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true);
destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor;
}
// we have correct destz now
@@ -2782,8 +2784,8 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle)
// @todo: replace with WorldObject::UpdateAllowedPositionZ
float NormalizeZforCollision(WorldObject* obj, float x, float y, float z)
{
- float ground = obj->GetMap()->GetHeight(obj->GetPhases(), x, y, MAX_HEIGHT, true);
- float floor = obj->GetMap()->GetHeight(obj->GetPhases(), x, y, z + 2.0f, true);
+ float ground = obj->GetMap()->GetHeight(obj->GetPhaseShift(), x, y, MAX_HEIGHT, true);
+ float floor = obj->GetMap()->GetHeight(obj->GetPhaseShift(), x, y, z + 2.0f, true);
float helper = std::fabs(ground - z) <= std::fabs(floor - z) ? ground : floor;
if (z > helper) // must be above ground
{
@@ -2832,7 +2834,7 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float
}
// check dynamic collision
- col = GetMap()->getObjectHitPos(GetPhases(), pos.m_positionX, pos.m_positionY, pos.m_positionZ + 0.5f, destx, desty, destz + 0.5f, destx, desty, destz, -0.5f);
+ col = GetMap()->getObjectHitPos(GetPhaseShift(), pos.m_positionX, pos.m_positionY, pos.m_positionZ + 0.5f, destx, desty, destz + 0.5f, destx, desty, destz, -0.5f);
// Collided with a gameobject
if (col)
@@ -2867,150 +2869,6 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float
pos.SetOrientation(GetOrientation());
}
-bool WorldObject::HasInPhaseList(uint32 phase)
-{
- return _phases.find(phase) != _phases.end();
-}
-
-// Updates Area based phases, does not remove phases from auras
-// Phases from gm commands are not taken into calculations, they can be lost!!
-void WorldObject::UpdateAreaAndZonePhase()
-{
- bool updateNeeded = false;
- PhaseInfo const& allAreasPhases = sObjectMgr->GetAreaAndZonePhases();
- uint32 zoneAndArea[] = { GetZoneId(), GetAreaId() };
-
- // We first remove all phases from other areas & zones
- for (auto itr = allAreasPhases.begin(); itr != allAreasPhases.end(); ++itr)
- for (PhaseInfoStruct const& phase : itr->second)
- if (!DB2Manager::IsInArea(GetAreaId(), itr->first))
- updateNeeded = SetInPhase(phase.Id, false, false) || updateNeeded; // not in area, remove phase, true if there was something removed
-
- // Then we add the phases from this area and zone if conditions are met
- // Zone is done before Area, so if Area does not meet condition, the phase will be removed
- for (uint32 area : zoneAndArea)
- {
- if (std::vector<PhaseInfoStruct> const* currentPhases = sObjectMgr->GetPhasesForArea(area))
- {
- for (PhaseInfoStruct const& phaseInfoStruct : *currentPhases)
- {
- bool apply = sConditionMgr->IsObjectMeetToConditions(this, phaseInfoStruct.Conditions);
-
- // add or remove phase depending of condition
- updateNeeded = SetInPhase(phaseInfoStruct.Id, false, apply) || updateNeeded;
- }
- }
- }
-
- // do not remove a phase if it would be removed by an area but we have the same phase from an aura
- if (Unit* unit = ToUnit())
- {
- Unit::AuraEffectList const& auraPhaseList = unit->GetAuraEffectsByType(SPELL_AURA_PHASE);
- for (Unit::AuraEffectList::const_iterator itr = auraPhaseList.begin(); itr != auraPhaseList.end(); ++itr)
- {
- uint32 phase = uint32((*itr)->GetMiscValueB());
- updateNeeded = SetInPhase(phase, false, true) || updateNeeded;
- }
- Unit::AuraEffectList const& auraPhaseGroupList = unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP);
- for (Unit::AuraEffectList::const_iterator itr = auraPhaseGroupList.begin(); itr != auraPhaseGroupList.end(); ++itr)
- {
- uint32 phaseGroup = uint32((*itr)->GetMiscValueB());
- std::set<uint32> phaseIDs = sDB2Manager.GetPhasesForGroup(phaseGroup);
- for (uint32 phase : phaseIDs)
- updateNeeded = SetInPhase(phase, false, true) || updateNeeded;
- }
- }
-
- // only update visibility and send packets if there was a change in the phase list
- if (updateNeeded && GetTypeId() == TYPEID_PLAYER && IsInWorld())
- ToPlayer()->GetSession()->SendSetPhaseShift(GetPhases(), GetTerrainSwaps(), GetWorldMapAreaSwaps());
-
- // only update visibilty once, to prevent objects appearing for a moment while adding in multiple phases
- if (updateNeeded && IsInWorld())
- UpdateObjectVisibility();
-}
-
-bool WorldObject::SetInPhase(uint32 id, bool update, bool apply)
-{
- if (id)
- {
- if (apply)
- {
- // do not run the updates if we are already in this phase
- if (!_phases.insert(id).second)
- return false;
- }
- else
- {
- auto phaseItr = _phases.find(id);
- if (phaseItr == _phases.end())
- return false;
-
- // if area phase passes the condition we should not remove it (ie: if remove called from aura remove)
- // this however breaks the .mod phase command, you wont be able to remove any area based phases with it
- if (std::vector<PhaseInfoStruct> const* phases = sObjectMgr->GetPhasesForArea(GetAreaId()))
- for (PhaseInfoStruct const& phase : *phases)
- if (id == phase.Id)
- if (sConditionMgr->IsObjectMeetToConditions(this, phase.Conditions))
- return false;
-
- _phases.erase(phaseItr);
- }
- }
-
- RebuildTerrainSwaps();
-
- if (update && IsInWorld())
- UpdateObjectVisibility();
-
- return true;
-}
-
-void WorldObject::CopyPhaseFrom(WorldObject* obj, bool update)
-{
- if (!obj)
- return;
-
- for (uint32 phase : obj->GetPhases())
- SetInPhase(phase, false, true);
-
- if (update && IsInWorld())
- UpdateObjectVisibility();
-}
-
-void WorldObject::ClearPhases(bool update)
-{
- _phases.clear();
-
- RebuildTerrainSwaps();
-
- if (update && IsInWorld())
- UpdateObjectVisibility();
-}
-
-bool WorldObject::IsInPhase(std::set<uint32> const& phases) const
-{
- // PhaseId 169 is the default fallback phase
- if (_phases.empty() && phases.empty())
- return true;
-
- if (_phases.empty() && phases.count(DEFAULT_PHASE) > 0)
- return true;
-
- if (phases.empty() && _phases.count(DEFAULT_PHASE) > 0)
- return true;
-
- return Trinity::Containers::Intersects(_phases.begin(), _phases.end(), phases.begin(), phases.end());
-}
-
-bool WorldObject::IsInPhase(WorldObject const* obj) const
-{
- if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster())
- return true;
-
- return IsInPhase(obj->GetPhases());
-}
-
void WorldObject::PlayDistanceSound(uint32 soundId, Player* target /*= nullptr*/)
{
if (target)
@@ -3165,66 +3023,6 @@ ObjectGuid WorldObject::GetTransGUID() const
return ObjectGuid::Empty;
}
-void WorldObject::RebuildTerrainSwaps()
-{
- // Clear all terrain swaps, will be rebuilt below
- // Reason for this is, multiple phases can have the same terrain swap, we should not remove the swap if another phase still use it
- _terrainSwaps.clear();
-
- // Check all applied phases for terrain swap and add it only once
- for (uint32 phaseId : _phases)
- {
- if (std::vector<uint32> const* swaps = sObjectMgr->GetPhaseTerrainSwaps(phaseId))
- {
- for (uint32 const& swap : *swaps)
- {
- // only add terrain swaps for current map
- MapEntry const* mapEntry = sMapStore.LookupEntry(swap);
- if (!mapEntry || mapEntry->ParentMapID != int32(GetMapId()))
- continue;
-
- if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap, this))
- _terrainSwaps.insert(swap);
- }
- }
- }
-
- // get default terrain swaps, only for current map always
- if (std::vector<uint32> const* mapSwaps = sObjectMgr->GetDefaultTerrainSwaps(GetMapId()))
- for (uint32 const& swap : *mapSwaps)
- if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap, this))
- _terrainSwaps.insert(swap);
-
- // online players have a game client with world map display
- if (GetTypeId() == TYPEID_PLAYER)
- RebuildWorldMapAreaSwaps();
-}
-
-void WorldObject::RebuildWorldMapAreaSwaps()
-{
- // Clear all world map area swaps, will be rebuilt below
- _worldMapAreaSwaps.clear();
-
- // get ALL default terrain swaps, if we are using it (condition is true)
- // send the worldmaparea for it, to see swapped worldmaparea in client from other maps too, not just from our current
- TerrainPhaseInfo const& defaults = sObjectMgr->GetDefaultTerrainSwapStore();
- for (TerrainPhaseInfo::const_iterator itr = defaults.begin(); itr != defaults.end(); ++itr)
- for (uint32 const& swap : itr->second)
- if (std::vector<uint32> const* uiMapSwaps = sObjectMgr->GetTerrainWorldMaps(swap))
- if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap, this))
- for (uint32 worldMapAreaId : *uiMapSwaps)
- _worldMapAreaSwaps.insert(worldMapAreaId);
-
- // Check all applied phases for world map area swaps
- for (uint32 phaseId : _phases)
- if (std::vector<uint32> const* swaps = sObjectMgr->GetPhaseTerrainSwaps(phaseId))
- for (uint32 const& swap : *swaps)
- if (std::vector<uint32> const* uiMapSwaps = sObjectMgr->GetTerrainWorldMaps(swap))
- if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap, this))
- for (uint32 worldMapAreaId : *uiMapSwaps)
- _worldMapAreaSwaps.insert(worldMapAreaId);
-}
-
template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>&, uint32, float) const;
template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque<GameObject*>&, uint32, float) const;
template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector<GameObject*>&, uint32, float) const;
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index db8e40a45e7..3dcc769b8ab 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -25,12 +25,11 @@
#include "MovementInfo.h"
#include "ObjectDefines.h"
#include "ObjectGuid.h"
+#include "PhaseShift.h"
#include "Position.h"
#include "SharedDefines.h"
-
#include "UpdateFields.h"
#include <list>
-#include <set>
#include <unordered_map>
class AreaTrigger;
@@ -408,20 +407,15 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
uint32 GetInstanceId() const { return m_InstanceId; }
- virtual bool SetInPhase(uint32 id, bool update, bool apply);
- void CopyPhaseFrom(WorldObject* obj, bool update = false);
- void UpdateAreaAndZonePhase();
- void ClearPhases(bool update = false);
- void RebuildTerrainSwaps();
- void RebuildWorldMapAreaSwaps();
- bool HasInPhaseList(uint32 phase);
- bool IsInPhase(uint32 phase) const { return _phases.find(phase) != _phases.end(); }
- bool IsInPhase(std::set<uint32> const& phases) const;
- bool IsInPhase(WorldObject const* obj) const;
- bool IsInTerrainSwap(uint32 terrainSwap) const { return _terrainSwaps.find(terrainSwap) != _terrainSwaps.end(); }
- std::set<uint32> const& GetPhases() const { return _phases; }
- std::set<uint32> const& GetTerrainSwaps() const { return _terrainSwaps; }
- std::set<uint32> const& GetWorldMapAreaSwaps() const { return _worldMapAreaSwaps; }
+ bool IsInPhase(WorldObject const* obj) const
+ {
+ return GetPhaseShift().CanSee(obj->GetPhaseShift());
+ }
+
+ PhaseShift& GetPhaseShift() { return _phaseShift; }
+ PhaseShift const& GetPhaseShift() const { return _phaseShift; }
+ PhaseShift& GetSuppressedPhaseShift() { return _suppressedPhaseShift; }
+ PhaseShift const& GetSuppressedPhaseShift() const { return _suppressedPhaseShift; }
int32 GetDBPhase() const { return _dbPhase; }
// if negative it is used as PhaseGroupId
@@ -606,9 +600,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
//uint32 m_mapId; // object at map with map_id
uint32 m_InstanceId; // in map copy with instance id
- std::set<uint32> _phases;
- std::set<uint32> _terrainSwaps;
- std::set<uint32> _worldMapAreaSwaps;
+ PhaseShift _phaseShift;
+ PhaseShift _suppressedPhaseShift; // contains phases for current area but not applied due to conditions
int32 _dbPhase;
uint16 m_notifyflags;
diff --git a/src/server/game/Entities/Object/ObjectDefines.h b/src/server/game/Entities/Object/ObjectDefines.h
index 72d5f80109c..4891da4e61c 100644
--- a/src/server/game/Entities/Object/ObjectDefines.h
+++ b/src/server/game/Entities/Object/ObjectDefines.h
@@ -38,8 +38,6 @@
#define NOMINAL_MELEE_RANGE 5.0f
#define MELEE_RANGE (NOMINAL_MELEE_RANGE - MIN_MELEE_REACH * 2) //center to center for players
-#define DEFAULT_PHASE 169
-
enum TempSummonType
{
TEMPSUMMON_TIMED_OR_DEAD_DESPAWN = 1, // despawns after a specified time OR when the creature disappears
diff --git a/src/server/game/Entities/Object/PhaseShift.cpp b/src/server/game/Entities/Object/PhaseShift.cpp
deleted file mode 100644
index 7bbf5dfe667..00000000000
--- a/src/server/game/Entities/Object/PhaseShift.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "PhaseShift.h"
diff --git a/src/server/game/Entities/Object/PhaseShift.h b/src/server/game/Entities/Object/PhaseShift.h
deleted file mode 100644
index e830938f41e..00000000000
--- a/src/server/game/Entities/Object/PhaseShift.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PhaseShift_h__
-#define PhaseShift_h__
-
-#include "Define.h"
-#include <set>
-
-class PhaseShift
-{
-private:
- std::set<uint32> _phases;
- std::set<uint32> _terrainSwaps;
- std::set<uint32> _worldMapAreaSwaps;
-};
-
-#endif // PhaseShift_h__
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 24f63d43472..3e08a2ad31f 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -25,6 +25,7 @@
#include "Map.h"
#include "ObjectMgr.h"
#include "PetPackets.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "Spell.h"
#include "SpellAuraEffects.h"
@@ -182,7 +183,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
if (!Create(map->GenerateLowGuid<HighGuid::Pet>(), map, petEntry))
return false;
- CopyPhaseFrom(owner);
+ PhasingHandler::InheritPhaseShift(this, owner);
setPetType(petType);
setFaction(owner->getFaction());
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index f3c115cd6d1..d5da4d8e66b 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -87,6 +87,7 @@
#include "OutdoorPvPMgr.h"
#include "Pet.h"
#include "PetPackets.h"
+#include "PhasingHandler.h"
#include "QueryHolder.h"
#include "QuestDef.h"
#include "QuestObjectiveCriteriaMgr.h"
@@ -2195,10 +2196,13 @@ void Player::SetGameMaster(bool on)
getHostileRefManager().setOnlineOfflineState(false);
CombatStopWithPets();
+ PhasingHandler::SetAlwaysVisible(GetPhaseShift(), true);
m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, GetSession()->GetSecurity());
}
else
{
+ PhasingHandler::SetAlwaysVisible(GetPhaseShift(), false);
+
m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON;
setFactionForRace(getRace());
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
@@ -6984,7 +6988,7 @@ void Player::UpdateArea(uint32 newArea)
UpdatePvPState(true);
UpdateAreaDependentAuras(newArea);
- UpdateAreaAndZonePhase();
+ PhasingHandler::OnAreaChange(this);
if (IsAreaThatActivatesPvpTalents(newArea))
EnablePvpRules();
@@ -7093,8 +7097,6 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
UpdateLocalChannels(newZone);
UpdateZoneDependentAuras(newZone);
-
- UpdateAreaAndZonePhase();
}
//If players are too far away from the duel flag... they lose the duel
@@ -16188,7 +16190,7 @@ void Player::SendQuestUpdate(uint32 questId)
}
UpdateForQuestWorldObjects();
- SendUpdatePhasing();
+ PhasingHandler::OnConditionChange(this);
}
QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver)
@@ -23820,6 +23822,8 @@ void Player::SendInitialPacketsAfterAddToMap()
SendRaidDifficulty((difficulty->Flags & DIFFICULTY_FLAG_LEGACY) != 0);
}
+ PhasingHandler::OnMapChange(this);
+
if (_garrison)
_garrison->SendRemoteInfo();
@@ -27751,7 +27755,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy
return nullptr;
}
- pet->CopyPhaseFrom(this);
+ PhasingHandler::InheritPhaseShift(pet, this);
pet->SetCreatorGUID(GetGUID());
pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction());
@@ -27895,16 +27899,6 @@ void Player::ValidateMovementInfo(MovementInfo* mi)
#undef REMOVE_VIOLATING_FLAGS
}
-void Player::SendUpdatePhasing()
-{
- if (!IsInWorld())
- return;
-
- RebuildTerrainSwaps(); // to set default map swaps
-
- GetSession()->SendSetPhaseShift(GetPhases(), GetTerrainSwaps(), GetWorldMapAreaSwaps());
-}
-
void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) const
{
WorldPackets::Spells::SupercededSpells supercededSpells;
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 11076546fd5..ebe275a0f0a 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2183,6 +2183,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
// currently visible objects at player client
GuidUnorderedSet m_clientGUIDs;
+ GuidUnorderedSet m_visibleTransports;
bool HaveAtClient(Object const* u) const;
@@ -2196,8 +2197,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void UpdateVisibilityOf(WorldObject* target);
void UpdateTriggerVisibility();
- void SendUpdatePhasing();
-
template<class T>
void UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow);
diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp
index cdfaa3f33c9..bd86313e004 100644
--- a/src/server/game/Entities/Transport/Transport.cpp
+++ b/src/server/game/Entities/Transport/Transport.cpp
@@ -24,6 +24,7 @@
#include "Log.h"
#include "MapManager.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "Spline.h"
@@ -326,13 +327,8 @@ Creature* Transport::CreateNPCPassenger(ObjectGuid::LowType guid, CreatureData c
return nullptr;
}
- if (data->phaseId)
- creature->SetInPhase(data->phaseId, false, true);
- else if (data->phaseGroup)
- for (auto phase : sDB2Manager.GetPhasesForGroup(data->phaseGroup))
- creature->SetInPhase(phase, false, true);
- else
- creature->CopyPhaseFrom(this);
+ PhasingHandler::InitDbPhaseShift(creature->GetPhaseShift(), data->phaseUseFlags, data->phaseId, data->phaseGroup);
+ PhasingHandler::InitDbVisibleMapId(creature->GetPhaseShift(), data->terrainSwapMap);
if (!map->AddToMap(creature))
{
@@ -375,6 +371,9 @@ GameObject* Transport::CreateGOPassenger(ObjectGuid::LowType guid, GameObjectDat
return nullptr;
}
+ PhasingHandler::InitDbPhaseShift(go->GetPhaseShift(), data->phaseUseFlags, data->phaseId, data->phaseGroup);
+ PhasingHandler::InitDbVisibleMapId(go->GetPhaseShift(), data->terrainSwapMap);
+
if (!map->AddToMap(go))
{
delete go;
@@ -439,12 +438,6 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu
}
}
- std::set<uint32> phases;
- if (summoner)
- phases = summoner->GetPhases();
- else
- phases = GetPhases(); // If there was no summoner, try to use the transport phases
-
TempSummon* summon = nullptr;
switch (mask)
{
@@ -475,8 +468,7 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu
return nullptr;
}
- for (uint32 phase : phases)
- summon->SetInPhase(phase, false, true);
+ PhasingHandler::InheritPhaseShift(summon, summoner ? static_cast<WorldObject*>(summoner) : static_cast<WorldObject*>(this));
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId);
diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h
index 03bd3bcb2c7..b3bdcae034c 100644
--- a/src/server/game/Entities/Transport/Transport.h
+++ b/src/server/game/Entities/Transport/Transport.h
@@ -27,7 +27,7 @@ struct CreatureData;
class TC_GAME_API Transport : public GameObject, public TransportBase
{
- friend Transport* TransportMgr::CreateTransport(uint32, ObjectGuid::LowType, Map*, uint32, uint32);
+ friend Transport* TransportMgr::CreateTransport(uint32, ObjectGuid::LowType, Map*, uint8, uint32, uint32);
Transport();
public:
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 719f58ad870..75590a0c44d 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -55,6 +55,7 @@
#include "PassiveAI.h"
#include "Pet.h"
#include "PetAI.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "PlayerAI.h"
#include "QuestDef.h"
@@ -3849,7 +3850,7 @@ void Unit::RemoveAurasWithAttribute(uint32 flags)
}
}
-void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid)
+void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/)
{
// single target auras from other casters
// Iterate m_ownedAuras - aura is marked as single target in Unit::AddAura (and pushed to m_ownedAuras).
@@ -3866,12 +3867,12 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid)
if (aura->GetCasterGUID() != GetGUID() && aura->IsSingleTarget())
{
- if (!newPhase && !phaseid)
+ if (!onPhaseChange)
RemoveOwnedAura(iter);
else
{
Unit* caster = aura->GetCaster();
- if (!caster || (newPhase && !caster->IsInPhase(newPhase)) || (!newPhase && !caster->IsInPhase(this)))
+ if (!caster || !caster->IsInPhase(this))
RemoveOwnedAura(iter);
else
++iter;
@@ -3886,7 +3887,7 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid)
for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
{
Aura* aura = *iter;
- if (aura->GetUnitOwner() != this && !aura->GetUnitOwner()->IsInPhase(newPhase))
+ if (aura->GetUnitOwner() != this && (!onPhaseChange || !aura->GetUnitOwner()->IsInPhase(this)))
{
aura->Remove();
iter = scAuras.begin();
@@ -9466,15 +9467,6 @@ int32 Unit::GetCreatePowers(Powers power) const
return 0;
}
-void Unit::AddToWorld()
-{
- if (!IsInWorld())
- {
- WorldObject::AddToWorld();
- }
- RebuildTerrainSwaps();
-}
-
void Unit::RemoveFromWorld()
{
// cleanup
@@ -10751,7 +10743,7 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
return false;
}
- pet->CopyPhaseFrom(this);
+ PhasingHandler::InheritPhaseShift(pet, this);
pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
// this enables pet details window (Shift+P)
@@ -11976,14 +11968,12 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, u
return missChance;
}
-bool Unit::SetInPhase(uint32 id, bool update, bool apply)
+void Unit::OnPhaseChange()
{
- bool res = WorldObject::SetInPhase(id, update, apply);
-
if (!IsInWorld())
- return res;
+ return;
- if (GetTypeId() == TYPEID_UNIT || (!ToPlayer()->IsGameMaster() && !ToPlayer()->GetSession()->PlayerLogout()))
+ if (GetTypeId() == TYPEID_UNIT || !ToPlayer()->GetSession()->PlayerLogout())
{
HostileRefManager& refManager = getHostileRefManager();
HostileReference* ref = refManager.getFirst();
@@ -12013,19 +12003,6 @@ bool Unit::SetInPhase(uint32 id, bool update, bool apply)
unit->getHostileRefManager().setOnlineOfflineState(ToCreature(), unit->IsInPhase(this));
}
}
-
- for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
- if ((*itr)->GetTypeId() == TYPEID_UNIT)
- (*itr)->SetInPhase(id, true, apply);
-
- for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
- if (!m_SummonSlot[i].IsEmpty())
- if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
- summon->SetInPhase(id, true, apply);
-
- RemoveNotOwnSingleTargetAuras(0, true);
-
- return res;
}
void Unit::UpdateObjectVisibility(bool forced)
@@ -12848,7 +12825,7 @@ void Unit::_ExitVehicle(Position const* exitPosition)
Movement::MoveSplineInit init(this);
// Creatures without inhabit type air should begin falling after exiting the vehicle
- if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(GetPhases(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), &height) + 0.1f)
+ if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), &height) + 0.1f)
init.SetFall();
init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false);
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 6a8b7d94817..b5a023620da 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -930,7 +930,6 @@ class TC_GAME_API Unit : public WorldObject
UnitAI* GetAI() { return i_AI; }
void SetAI(UnitAI* newAI) { i_AI = newAI; }
- void AddToWorld() override;
void RemoveFromWorld() override;
void CleanupBeforeRemoveFromMap(bool finalCleanup);
@@ -1436,7 +1435,7 @@ class TC_GAME_API Unit : public WorldObject
void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, Unit* stealer);
void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid);
void RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID = ObjectGuid::Empty, Aura* except = NULL, bool negative = true, bool positive = true);
- void RemoveNotOwnSingleTargetAuras(uint32 newPhase = 0x0, bool phaseid = false);
+ void RemoveNotOwnSingleTargetAuras(bool onPhaseChange = false);
template <typename InterruptFlags>
void RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except = 0);
void RemoveAurasWithAttribute(uint32 flags);
@@ -1625,7 +1624,7 @@ class TC_GAME_API Unit : public WorldObject
void SetVisible(bool x);
// common function for visibility checks for player/creatures with detection code
- bool SetInPhase(uint32 id, bool update, bool apply) override;
+ void OnPhaseChange();
void UpdateObjectVisibility(bool forced = true) override;
SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY];
diff --git a/src/server/game/Garrison/Garrison.cpp b/src/server/game/Garrison/Garrison.cpp
index 1e2766a93d5..4dc4db59775 100644
--- a/src/server/game/Garrison/Garrison.cpp
+++ b/src/server/game/Garrison/Garrison.cpp
@@ -25,6 +25,7 @@
#include "Map.h"
#include "MapManager.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "VehicleDefines.h"
@@ -235,7 +236,7 @@ bool Garrison::Create(uint32 garrSiteId)
WorldPackets::Garrison::GarrisonCreateResult garrisonCreateResult;
garrisonCreateResult.GarrSiteLevelID = _siteLevel->ID;
_owner->SendDirectMessage(garrisonCreateResult.Write());
- _owner->SendUpdatePhasing();
+ PhasingHandler::OnConditionChange(_owner);
SendRemoteInfo();
return true;
}
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 8a8651f3aa0..78cd1e7e5b9 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1872,8 +1872,8 @@ void ObjectMgr::LoadCreatures()
QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, "
// 11 12 13 14 15 16 17 18 19 20 21
"currentwaypoint, curhealth, curmana, MovementType, spawnMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.unit_flags2, creature.unit_flags3, "
- // 22 23 24 25
- "creature.dynamicflags, creature.phaseid, creature.phasegroup, creature.ScriptName "
+ // 22 23 24 25 26 27
+ "creature.dynamicflags, creature.phaseUseFlags, creature.phaseid, creature.phasegroup, creature.terrainSwapMap, creature.ScriptName "
"FROM creature "
"LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid "
"LEFT OUTER JOIN pool_creature ON creature.guid = pool_creature.guid");
@@ -1930,9 +1930,11 @@ void ObjectMgr::LoadCreatures()
data.unit_flags2 = fields[20].GetUInt32();
data.unit_flags3 = fields[21].GetUInt32();
data.dynamicflags = fields[22].GetUInt32();
- data.phaseId = fields[23].GetUInt32();
- data.phaseGroup = fields[24].GetUInt32();
- data.ScriptId = GetScriptId(fields[25].GetString());
+ data.phaseUseFlags = fields[23].GetUInt8();
+ data.phaseId = fields[24].GetUInt32();
+ data.phaseGroup = fields[25].GetUInt32();
+ data.terrainSwapMap = fields[26].GetInt32();
+ data.ScriptId = GetScriptId(fields[27].GetString());
if (!data.ScriptId)
data.ScriptId = cInfo->ScriptID;
@@ -2020,6 +2022,19 @@ void ObjectMgr::LoadCreatures()
data.orientation = Position::NormalizeOrientation(data.orientation);
}
+ if (data.phaseUseFlags & ~PHASE_USE_FLAGS_ALL)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) has unknown `phaseUseFlags` set, removed unknown value.", guid, data.id);
+ data.phaseUseFlags &= PHASE_USE_FLAGS_ALL;
+ }
+
+ if (data.phaseUseFlags & PHASE_USE_FLAGS_ALWAYS_VISIBLE && data.phaseUseFlags & PHASE_USE_FLAGS_INVERSE)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE,"
+ " removing PHASE_USE_FLAGS_INVERSE.", guid, data.id);
+ data.phaseUseFlags &= ~PHASE_USE_FLAGS_INVERSE;
+ }
+
if (data.phaseGroup && data.phaseId)
{
TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.id);
@@ -2037,13 +2052,28 @@ void ObjectMgr::LoadCreatures()
if (data.phaseGroup)
{
- if (sDB2Manager.GetPhasesForGroup(data.phaseGroup).empty())
+ if (!sDB2Manager.GetPhasesForGroup(data.phaseGroup))
{
TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with `phasegroup` %u does not exist, set to 0", guid, data.id, data.phaseGroup);
data.phaseGroup = 0;
}
}
+ if (data.terrainSwapMap != -1)
+ {
+ MapEntry const* terrainSwapEntry = sMapStore.LookupEntry(data.terrainSwapMap);
+ if (!terrainSwapEntry)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u does not exist, set to -1", guid, data.id, data.terrainSwapMap);
+ data.terrainSwapMap = -1;
+ }
+ else if (terrainSwapEntry->ParentMapID != data.mapid)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u which cannot be used on spawn map, set to -1", guid, data.id, data.terrainSwapMap);
+ data.terrainSwapMap = -1;
+ }
+ }
+
if (sWorld->getBoolConfig(CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA))
{
uint32 zoneId = 0;
@@ -2202,8 +2232,8 @@ void ObjectMgr::LoadGameobjects()
QueryResult result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation, "
// 7 8 9 10 11 12 13 14 15 16
"rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, eventEntry, pool_entry, "
- // 17 18 19
- "phaseid, phasegroup, ScriptName "
+ // 17 18 19 20 21
+ "phaseUseFlags, phaseid, phasegroup, terrainSwapMap, ScriptName "
"FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid "
"LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid");
@@ -2317,8 +2347,22 @@ void ObjectMgr::LoadGameobjects()
int16 gameEvent = fields[15].GetInt8();
uint32 PoolId = fields[16].GetUInt32();
- data.phaseId = fields[17].GetUInt32();
- data.phaseGroup = fields[18].GetUInt32();
+ data.phaseUseFlags = fields[17].GetUInt8();
+ data.phaseId = fields[18].GetUInt32();
+ data.phaseGroup = fields[19].GetUInt32();
+
+ if (data.phaseUseFlags & ~PHASE_USE_FLAGS_ALL)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) has unknown `phaseUseFlags` set, removed unknown value.", guid, data.id);
+ data.phaseUseFlags &= PHASE_USE_FLAGS_ALL;
+ }
+
+ if (data.phaseUseFlags & PHASE_USE_FLAGS_ALWAYS_VISIBLE && data.phaseUseFlags & PHASE_USE_FLAGS_INVERSE)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE,"
+ " removing PHASE_USE_FLAGS_INVERSE.", guid, data.id);
+ data.phaseUseFlags &= ~PHASE_USE_FLAGS_INVERSE;
+ }
if (data.phaseGroup && data.phaseId)
{
@@ -2337,14 +2381,30 @@ void ObjectMgr::LoadGameobjects()
if (data.phaseGroup)
{
- if (sDB2Manager.GetPhasesForGroup(data.phaseGroup).empty())
+ if (!sDB2Manager.GetPhasesForGroup(data.phaseGroup))
{
TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) with `phaseGroup` %u does not exist, set to 0", guid, data.id, data.phaseGroup);
data.phaseGroup = 0;
}
}
- data.ScriptId = GetScriptId(fields[19].GetString());
+ data.terrainSwapMap = fields[20].GetInt32();
+ if (data.terrainSwapMap != -1)
+ {
+ MapEntry const* terrainSwapEntry = sMapStore.LookupEntry(data.terrainSwapMap);
+ if (!terrainSwapEntry)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u does not exist, set to -1", guid, data.id, data.terrainSwapMap);
+ data.terrainSwapMap = -1;
+ }
+ else if (terrainSwapEntry->ParentMapID != data.mapid)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) with `terrainSwapMap` %u which cannot be used on spawn map, set to -1", guid, data.id, data.terrainSwapMap);
+ data.terrainSwapMap = -1;
+ }
+ }
+
+ data.ScriptId = GetScriptId(fields[21].GetString());
if (!data.ScriptId)
data.ScriptId = gInfo->ScriptId;
@@ -9394,18 +9454,42 @@ void ObjectMgr::LoadFactionChangeTitles()
TC_LOG_INFO("server.loading", ">> Loaded %u faction change title pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
-void ObjectMgr::LoadTerrainSwapDefaults()
+void ObjectMgr::LoadPhases()
+{
+ for (PhaseEntry const* phase : sPhaseStore)
+ _phaseInfoById.emplace(std::make_pair(phase->ID, PhaseInfoStruct{ phase->ID, std::unordered_set<uint32>{} }));
+
+ for (MapEntry const* map : sMapStore)
+ if (map->ParentMapID != -1)
+ _terrainSwapInfoById.emplace(std::make_pair(map->ID, TerrainSwapInfo{ map->ID, std::vector<uint32>{} }));
+
+ TC_LOG_INFO("server.loading", "Loading Terrain World Map definitions...");
+ LoadTerrainWorldMaps();
+
+ TC_LOG_INFO("server.loading", "Loading Terrain Swap Default definitions...");
+ LoadTerrainSwapDefaults();
+
+ TC_LOG_INFO("server.loading", "Loading Phase Area definitions...");
+ LoadAreaPhases();
+}
+
+void ObjectMgr::UnloadPhaseConditions()
{
- _terrainMapDefaultStore.clear();
+ for (auto itr = _phaseInfoByArea.begin(); itr != _phaseInfoByArea.end(); ++itr)
+ for (PhaseAreaInfo& phase : itr->second)
+ phase.Conditions.clear();
+}
+void ObjectMgr::LoadTerrainWorldMaps()
+{
uint32 oldMSTime = getMSTime();
- // 0 1
- QueryResult result = WorldDatabase.Query("SELECT MapId, TerrainSwapMap FROM `terrain_swap_defaults`");
+ // 0 1
+ QueryResult result = WorldDatabase.Query("SELECT TerrainSwapMap, WorldMapArea FROM `terrain_worldmap`");
if (!result)
{
- TC_LOG_INFO("server.loading", ">> Loaded 0 terrain swap defaults. DB table `terrain_swap_defaults` is empty.");
+ TC_LOG_INFO("server.loading", ">> Loaded 0 terrain world maps. DB table `terrain_worldmap` is empty.");
return;
}
@@ -9415,41 +9499,40 @@ void ObjectMgr::LoadTerrainSwapDefaults()
Field* fields = result->Fetch();
uint32 mapId = fields[0].GetUInt32();
+ uint32 worldMapArea = fields[1].GetUInt32();
if (!sMapStore.LookupEntry(mapId))
{
- TC_LOG_ERROR("sql.sql", "Map %u defined in `terrain_swap_defaults` does not exist, skipped.", mapId);
+ TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_worldmap` does not exist, skipped.", mapId);
continue;
}
- uint32 terrainSwap = fields[1].GetUInt32();
-
- if (!sMapStore.LookupEntry(terrainSwap))
+ if (!sWorldMapAreaStore.LookupEntry(worldMapArea))
{
- TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_swap_defaults` does not exist, skipped.", terrainSwap);
+ TC_LOG_ERROR("sql.sql", "WorldMapArea %u defined in `terrain_worldmap` does not exist, skipped.", worldMapArea);
continue;
}
- _terrainMapDefaultStore[mapId].push_back(terrainSwap);
+ TerrainSwapInfo* terrainSwapInfo = &_terrainSwapInfoById[mapId];
+ terrainSwapInfo->Id = mapId;
+ terrainSwapInfo->UiWorldMapAreaIDSwaps.push_back(worldMapArea);
++count;
} while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u terrain swap defaults in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Loaded %u terrain world maps in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
}
-void ObjectMgr::LoadTerrainPhaseInfo()
+void ObjectMgr::LoadTerrainSwapDefaults()
{
- _terrainPhaseInfoStore.clear();
-
uint32 oldMSTime = getMSTime();
// 0 1
- QueryResult result = WorldDatabase.Query("SELECT Id, TerrainSwapMap FROM `terrain_phase_info`");
+ QueryResult result = WorldDatabase.Query("SELECT MapId, TerrainSwapMap FROM `terrain_swap_defaults`");
if (!result)
{
- TC_LOG_INFO("server.loading", ">> Loaded 0 terrain phase infos. DB table `terrain_phase_info` is empty.");
+ TC_LOG_INFO("server.loading", ">> Loaded 0 terrain swap defaults. DB table `terrain_swap_defaults` is empty.");
return;
}
@@ -9458,92 +9541,130 @@ void ObjectMgr::LoadTerrainPhaseInfo()
{
Field* fields = result->Fetch();
- uint32 phaseId = fields[0].GetUInt32();
+ uint32 mapId = fields[0].GetUInt32();
- if (!sPhaseStore.LookupEntry(phaseId))
+ if (!sMapStore.LookupEntry(mapId))
{
- TC_LOG_ERROR("sql.sql", "Phase %u defined in `terrain_phase_info` does not exist, skipped.", phaseId);
+ TC_LOG_ERROR("sql.sql", "Map %u defined in `terrain_swap_defaults` does not exist, skipped.", mapId);
continue;
}
uint32 terrainSwap = fields[1].GetUInt32();
- _terrainPhaseInfoStore[phaseId].push_back(terrainSwap);
+ if (!sMapStore.LookupEntry(terrainSwap))
+ {
+ TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_swap_defaults` does not exist, skipped.", terrainSwap);
+ continue;
+ }
+
+ TerrainSwapInfo* terrainSwapInfo = &_terrainSwapInfoById[terrainSwap];
+ terrainSwapInfo->Id = terrainSwap;
+ _terrainSwapInfoByMap[mapId].push_back(terrainSwapInfo);
++count;
- }
- while (result->NextRow());
+ } while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u terrain phase infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Loaded %u terrain swap defaults in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
}
-void ObjectMgr::LoadTerrainWorldMaps()
+void ObjectMgr::LoadAreaPhases()
{
- _terrainWorldMapStore.clear();
-
uint32 oldMSTime = getMSTime();
- // 0 1
- QueryResult result = WorldDatabase.Query("SELECT TerrainSwapMap, WorldMapArea FROM `terrain_worldmap`");
+ // 0 1
+ QueryResult result = WorldDatabase.Query("SELECT AreaId, PhaseId FROM `phase_area`");
if (!result)
{
- TC_LOG_INFO("server.loading", ">> Loaded 0 terrain world maps. DB table `terrain_worldmap` is empty.");
+ TC_LOG_INFO("server.loading", ">> Loaded 0 phase areas. DB table `phase_area` is empty.");
return;
}
+ auto getOrCreatePhaseIfMissing = [this](uint32 phaseId)
+ {
+ PhaseInfoStruct* phaseInfo = &_phaseInfoById[phaseId];
+ phaseInfo->Id = phaseId;
+ return phaseInfo;
+ };
+
uint32 count = 0;
do
{
Field* fields = result->Fetch();
-
- uint32 mapId = fields[0].GetUInt32();
-
- if (!sMapStore.LookupEntry(mapId))
+ uint32 area = fields[0].GetUInt32();
+ uint32 phaseId = fields[1].GetUInt32();
+ if (!sAreaTableStore.LookupEntry(area))
{
- TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_worldmap` does not exist, skipped.", mapId);
+ TC_LOG_ERROR("sql.sql", "Area %u defined in `phase_area` does not exist, skipped.", area);
continue;
}
- uint32 worldMapArea = fields[1].GetUInt32();
+ if (!sPhaseStore.LookupEntry(phaseId))
+ {
+ TC_LOG_ERROR("sql.sql", "Phase %u defined in `phase_area` does not exist, skipped.", phaseId);
+ continue;
+ }
- _terrainWorldMapStore[mapId].push_back(worldMapArea);
+ PhaseInfoStruct* phase = getOrCreatePhaseIfMissing(phaseId);
+ phase->Areas.insert(area);
+ _phaseInfoByArea[area].emplace_back(phase);
++count;
} while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u terrain world maps in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
-}
-
-void ObjectMgr::LoadAreaPhases()
-{
- _phases.clear();
+ for (auto itr = _phaseInfoByArea.begin(); itr != _phaseInfoByArea.end(); ++itr)
+ {
+ for (PhaseAreaInfo& phase : itr->second)
+ {
+ uint32 parentAreaId = itr->first;
+ do
+ {
+ AreaTableEntry const* area = sAreaTableStore.LookupEntry(parentAreaId);
+ if (!area)
+ break;
- uint32 oldMSTime = getMSTime();
+ parentAreaId = area->ParentAreaID;
+ if (!parentAreaId)
+ break;
- // 0 1
- QueryResult result = WorldDatabase.Query("SELECT AreaId, PhaseId FROM `phase_area`");
+ if (std::vector<PhaseAreaInfo>* parentAreaPhases = Trinity::Containers::MapGetValuePtr(_phaseInfoByArea, parentAreaId))
+ for (PhaseAreaInfo& parentAreaPhase : *parentAreaPhases)
+ if (parentAreaPhase.PhaseInfo->Id == phase.PhaseInfo->Id)
+ parentAreaPhase.SubAreaExclusions.insert(itr->first);
- if (!result)
- {
- TC_LOG_INFO("server.loading", ">> Loaded 0 phase areas. DB table `phase_area` is empty.");
- return;
+ } while (true);
+ }
}
- uint32 count = 0;
- do
+ TC_LOG_INFO("server.loading", ">> Loaded %u phase areas in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+bool PhaseInfoStruct::IsAllowedInArea(uint32 areaId) const
+{
+ return std::any_of(Areas.begin(), Areas.end(), [areaId](uint32 areaToCheck)
{
- Field* fields = result->Fetch();
+ return DB2Manager::IsInArea(areaId, areaToCheck);
+ });
+}
- PhaseInfoStruct phase;
- uint32 area = fields[0].GetUInt32();
- phase.Id = fields[1].GetUInt32();
- _phases[area].push_back(phase);
+PhaseInfoStruct const* ObjectMgr::GetPhaseInfo(uint32 phaseId) const
+{
+ return Trinity::Containers::MapGetValuePtr(_phaseInfoById, phaseId);
+}
- ++count;
- } while (result->NextRow());
+std::vector<PhaseAreaInfo> const* ObjectMgr::GetPhasesForArea(uint32 areaId) const
+{
+ return Trinity::Containers::MapGetValuePtr(_phaseInfoByArea, areaId);
+}
- TC_LOG_INFO("server.loading", ">> Loaded %u phase areas in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
+TerrainSwapInfo const* ObjectMgr::GetTerrainSwapInfo(uint32 terrainSwapId) const
+{
+ return Trinity::Containers::MapGetValuePtr(_terrainSwapInfoById, terrainSwapId);
+}
+
+std::vector<TerrainSwapInfo*> const* ObjectMgr::GetTerrainSwapsForMap(uint32 mapId) const
+{
+ return Trinity::Containers::MapGetValuePtr(_terrainSwapInfoByMap, mapId);
}
GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry) const
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 34824b704d4..6812f3ece18 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -892,15 +892,28 @@ struct DungeonEncounter
typedef std::list<DungeonEncounter const*> DungeonEncounterList;
typedef std::unordered_map<uint64, DungeonEncounterList> DungeonEncounterContainer;
+struct TerrainSwapInfo
+{
+ uint32 Id;
+ std::vector<uint32> UiWorldMapAreaIDSwaps;
+};
+
struct PhaseInfoStruct
{
uint32 Id;
- ConditionContainer Conditions;
+ std::unordered_set<uint32> Areas;
+
+ bool IsAllowedInArea(uint32 areaId) const;
};
-typedef std::unordered_map<uint32, std::vector<uint32 /*id*/>> TerrainPhaseInfo; // terrain swap
-typedef std::unordered_map<uint32, std::vector<uint32>> TerrainUIPhaseInfo; // worldmaparea swap
-typedef std::unordered_map<uint32, std::vector<PhaseInfoStruct>> PhaseInfo; // phase
+struct PhaseAreaInfo
+{
+ PhaseAreaInfo(PhaseInfoStruct const* phaseInfo) : PhaseInfo(phaseInfo) { }
+
+ PhaseInfoStruct const* PhaseInfo;
+ std::unordered_set<uint32> SubAreaExclusions;
+ ConditionContainer Conditions;
+};
struct RaceUnlockRequirement
{
@@ -1249,7 +1262,9 @@ class TC_GAME_API ObjectMgr
void LoadTrainers();
void LoadCreatureDefaultTrainers();
- void LoadTerrainPhaseInfo();
+ void LoadPhases();
+ void UnloadPhaseConditions();
+
void LoadTerrainSwapDefaults();
void LoadTerrainWorldMaps();
void LoadAreaPhases();
@@ -1513,36 +1528,6 @@ class TC_GAME_API ObjectMgr
return _gossipMenuItemsStore.equal_range(uiMenuId);
}
- std::vector<uint32> const* GetPhaseTerrainSwaps(uint32 phaseid) const
- {
- auto itr = _terrainPhaseInfoStore.find(phaseid);
- return itr != _terrainPhaseInfoStore.end() ? &itr->second : nullptr;
- }
- std::vector<uint32> const* GetDefaultTerrainSwaps(uint32 mapid) const
- {
- auto itr = _terrainMapDefaultStore.find(mapid);
- return itr != _terrainMapDefaultStore.end() ? &itr->second : nullptr;
- }
- std::vector<uint32> const* GetTerrainWorldMaps(uint32 terrainId) const
- {
- auto itr = _terrainWorldMapStore.find(terrainId);
- return itr != _terrainWorldMapStore.end() ? &itr->second : nullptr;
- }
- std::vector<PhaseInfoStruct> const* GetPhasesForArea(uint32 area) const
- {
- auto itr = _phases.find(area);
- return itr != _phases.end() ? &itr->second : nullptr;
- }
- TerrainPhaseInfo const& GetDefaultTerrainSwapStore() const { return _terrainMapDefaultStore; }
- PhaseInfo const& GetAreaAndZonePhases() const { return _phases; }
- // condition loading helpers
- std::vector<PhaseInfoStruct>* GetPhasesForAreaOrZoneForLoading(uint32 areaOrZone)
- {
- auto itr = _phases.find(areaOrZone);
- return itr != _phases.end() ? &itr->second : nullptr;
- }
- PhaseInfo& GetAreaAndZonePhasesForLoading() { return _phases; }
-
// for wintergrasp only
GraveYardContainer GraveYardStore;
@@ -1684,10 +1669,17 @@ class TC_GAME_API ObjectMgr
PageTextContainer _pageTextStore;
InstanceTemplateContainer _instanceTemplateStore;
- TerrainPhaseInfo _terrainPhaseInfoStore;
- TerrainPhaseInfo _terrainMapDefaultStore;
- TerrainUIPhaseInfo _terrainWorldMapStore;
- PhaseInfo _phases;
+ public:
+ PhaseInfoStruct const* GetPhaseInfo(uint32 phaseId) const;
+ std::vector<PhaseAreaInfo> const* GetPhasesForArea(uint32 areaId) const;
+ TerrainSwapInfo const* GetTerrainSwapInfo(uint32 terrainSwapId) const;
+ std::vector<TerrainSwapInfo*> const* GetTerrainSwapsForMap(uint32 mapId) const;
+
+ private:
+ std::unordered_map<uint32, PhaseInfoStruct> _phaseInfoById;
+ std::unordered_map<uint32, TerrainSwapInfo> _terrainSwapInfoById;
+ std::unordered_map<uint32, std::vector<PhaseAreaInfo>> _phaseInfoByArea;
+ std::unordered_map<uint32, std::vector<TerrainSwapInfo*>> _terrainSwapInfoByMap;
private:
void LoadScripts(ScriptsType type);
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 44965fbd8e6..296cd80e323 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -1062,17 +1062,6 @@ void WorldSession::HandleUITimeRequest(WorldPackets::Misc::UITimeRequest& /*requ
SendPacket(response.Write());
}
-void WorldSession::SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps, std::set<uint32> const& worldMapAreaSwaps)
-{
- WorldPackets::Misc::PhaseShift phaseShift;
- phaseShift.ClientGUID = _player->GetGUID();
- phaseShift.PersonalGUID = _player->GetGUID();
- phaseShift.PhaseShifts = phaseIds;
- phaseShift.VisibleMapIDs = terrainswaps;
- phaseShift.UiWorldMapAreaIDSwaps = worldMapAreaSwaps;
- SendPacket(phaseShift.Write());
-}
-
void WorldSession::HandleInstanceLockResponse(WorldPackets::Instance::InstanceLockResponse& packet)
{
if (!_player->HasPendingBind())
diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp
index 7c8048d8a73..273bf287821 100644
--- a/src/server/game/Handlers/QueryHandler.cpp
+++ b/src/server/game/Handlers/QueryHandler.cpp
@@ -204,7 +204,7 @@ void WorldSession::HandleQueryCorpseLocation(WorldPackets::Query::QueryCorpseLoc
mapID = corpseMapEntry->CorpseMapID;
x = corpseMapEntry->Corpse.X;
y = corpseMapEntry->Corpse.Y;
- z = entranceMap->GetHeight(player->GetPhases(), x, y, MAX_HEIGHT);
+ z = entranceMap->GetHeight(player->GetPhaseShift(), x, y, MAX_HEIGHT);
}
}
}
diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp
index 563388f64c1..78eb27430b6 100644
--- a/src/server/game/Instances/InstanceScript.cpp
+++ b/src/server/game/Instances/InstanceScript.cpp
@@ -32,6 +32,7 @@
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Pet.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "RBAC.h"
#include "ScriptMgr.h"
@@ -762,7 +763,7 @@ void InstanceScript::UpdatePhasing()
Map::PlayerList const& players = instance->GetPlayers();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource())
- player->SendUpdatePhasing();
+ PhasingHandler::SendToPlayer(player);
}
std::string InstanceScript::GetBossStateName(uint8 state)
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index ceb50e2e985..6ffa688ca08 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -41,6 +41,7 @@
#include "ObjectGridLoader.h"
#include "ObjectMgr.h"
#include "Pet.h"
+#include "PhasingHandler.h"
#include "ScriptMgr.h"
#include "Transport.h"
#include "Vehicle.h"
@@ -568,7 +569,7 @@ bool Map::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
player->m_clientGUIDs.clear();
player->UpdateObjectVisibility(false);
- player->SendUpdatePhasing();
+ PhasingHandler::SendToPlayer(player);
if (player->IsAlive())
ConvertCorpseToBones(player->GetGUID());
@@ -631,8 +632,6 @@ bool Map::AddToMap(T* obj)
if (obj->isActiveObject())
AddToActive(obj);
- obj->RebuildTerrainSwaps();
-
//something, such as vehicle, needs to be update immediately
//also, trigger needs to cast spell, if not update, cannot see visual
obj->UpdateObjectVisibilityOnCreate();
@@ -665,6 +664,7 @@ bool Map::AddToMap(Transport* obj)
{
UpdateData data(GetId());
obj->BuildCreateUpdateBlockForPlayer(&data, itr->GetSource());
+ itr->GetSource()->m_visibleTransports.insert(obj->GetGUID());
WorldPacket packet;
data.BuildPacket(&packet);
itr->GetSource()->SendDirectMessage(&packet);
@@ -969,8 +969,13 @@ void Map::RemoveFromMap(Transport* obj, bool remove)
WorldPacket packet;
data.BuildPacket(&packet);
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ {
if (itr->GetSource()->GetTransport() != obj)
+ {
itr->GetSource()->SendDirectMessage(&packet);
+ itr->GetSource()->m_visibleTransports.erase(obj->GetGUID());
+ }
+ }
}
if (_transportsUpdateIter != _transports.end())
@@ -2495,12 +2500,12 @@ inline GridMap* Map::GetGrid(float x, float y)
return GridMaps[gx][gy];
}
-float Map::GetWaterOrGroundLevel(std::set<uint32> const& phases, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/) const
+float Map::GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/) const
{
if (const_cast<Map*>(this)->GetGrid(x, y))
{
// we need ground level (including grid height version) for proper return water level in point
- float ground_z = GetHeight(phases, x, y, z, true, 50.0f);
+ float ground_z = GetHeight(phaseShift, x, y, z, true, 50.0f);
if (ground)
*ground = ground_z;
@@ -2789,19 +2794,19 @@ float Map::GetWaterLevel(float x, float y) const
return 0;
}
-bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, std::set<uint32> const& phases) const
+bool Map::isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2) const
{
return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2)
- && _dynamicTree.isInLineOfSight({ x1, y1, z1 }, { x2, y2, z2 }, phases);
+ && _dynamicTree.isInLineOfSight({ x1, y1, z1 }, { x2, y2, z2 }, phaseShift);
}
-bool Map::getObjectHitPos(std::set<uint32> const& phases, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist)
+bool Map::getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist)
{
G3D::Vector3 startPos(x1, y1, z1);
G3D::Vector3 dstPos(x2, y2, z2);
G3D::Vector3 resultPos;
- bool result = _dynamicTree.getObjectHitPos(phases, startPos, dstPos, resultPos, modifyDist);
+ bool result = _dynamicTree.getObjectHitPos(startPos, dstPos, resultPos, modifyDist, phaseShift);
rx = resultPos.x;
ry = resultPos.y;
@@ -2809,9 +2814,9 @@ bool Map::getObjectHitPos(std::set<uint32> const& phases, float x1, float y1, fl
return result;
}
-float Map::GetHeight(std::set<uint32> const& phases, float x, float y, float z, bool vmap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
+float Map::GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
{
- return std::max<float>(GetHeight(x, y, z, vmap, maxSearchDist), _dynamicTree.getHeight(x, y, z, maxSearchDist, phases));
+ return std::max<float>(GetHeight(x, y, z, vmap, maxSearchDist), _dynamicTree.getHeight(x, y, z, maxSearchDist, phaseShift));
}
bool Map::IsInWater(float x, float y, float pZ, LiquidData* data) const
@@ -2858,6 +2863,7 @@ void Map::SendInitSelf(Player* player)
if (Transport* transport = player->GetTransport())
{
transport->BuildCreateUpdateBlockForPlayer(&data, player);
+ player->m_visibleTransports.insert(transport->GetGUID());
}
// build data for self presence in world at own client (one time for map)
@@ -2865,9 +2871,9 @@ void Map::SendInitSelf(Player* player)
// build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
if (Transport* transport = player->GetTransport())
- for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
- if (player != (*itr) && player->HaveAtClient(*itr))
- (*itr)->BuildCreateUpdateBlockForPlayer(&data, player);
+ for (WorldObject* passenger : transport->GetPassengers())
+ if (player != passenger && player->HaveAtClient(passenger))
+ passenger->BuildCreateUpdateBlockForPlayer(&data, player);
WorldPacket packet;
data.BuildPacket(&packet);
@@ -2878,9 +2884,14 @@ void Map::SendInitTransports(Player* player)
{
// Hack to send out transports
UpdateData transData(player->GetMapId());
- for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i)
- if (*i != player->GetTransport() && player->IsInPhase(*i))
- (*i)->BuildCreateUpdateBlockForPlayer(&transData, player);
+ for (Transport* transport : _transports)
+ {
+ if (transport != player->GetTransport() && player->IsInPhase(transport))
+ {
+ transport->BuildCreateUpdateBlockForPlayer(&transData, player);
+ player->m_visibleTransports.insert(transport->GetGUID());
+ }
+ }
WorldPacket packet;
transData.BuildPacket(&packet);
@@ -2891,28 +2902,40 @@ void Map::SendRemoveTransports(Player* player)
{
// Hack to send out transports
UpdateData transData(player->GetMapId());
- for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i)
- if (*i != player->GetTransport())
- (*i)->BuildOutOfRangeUpdateBlock(&transData);
+ for (Transport* transport : _transports)
+ {
+ if (transport != player->GetTransport())
+ {
+ transport->BuildOutOfRangeUpdateBlock(&transData);
+ player->m_visibleTransports.erase(transport->GetGUID());
+ }
+ }
WorldPacket packet;
transData.BuildPacket(&packet);
player->GetSession()->SendPacket(&packet);
}
-void Map::SendUpdateTransportVisibility(Player* player, std::set<uint32> const& previousPhases)
+void Map::SendUpdateTransportVisibility(Player* player)
{
// Hack to send out transports
UpdateData transData(player->GetMapId());
- for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i)
+ for (Transport* transport : _transports)
{
- if (*i == player->GetTransport())
- continue;
-
- if (player->IsInPhase(*i) && !Trinity::Containers::Intersects(previousPhases.begin(), previousPhases.end(), (*i)->GetPhases().begin(), (*i)->GetPhases().end()))
- (*i)->BuildCreateUpdateBlockForPlayer(&transData, player);
- else if (!player->IsInPhase(*i))
- (*i)->BuildOutOfRangeUpdateBlock(&transData);
+ auto transportItr = player->m_visibleTransports.find(transport->GetGUID());
+ if (player->IsInPhase(transport))
+ {
+ if (transportItr == player->m_visibleTransports.end())
+ {
+ transport->BuildCreateUpdateBlockForPlayer(&transData, player);
+ player->m_visibleTransports.insert(transport->GetGUID());
+ }
+ }
+ else if (transportItr != player->m_visibleTransports.end())
+ {
+ transport->BuildOutOfRangeUpdateBlock(&transData);
+ player->m_visibleTransports.erase(transportItr);
+ }
}
WorldPacket packet;
@@ -4030,8 +4053,8 @@ void Map::LoadCorpseData()
continue;
}
- for (auto phaseId : phases[guid])
- corpse->SetInPhase(phaseId, false, true);
+ for (uint32 phaseId : phases[guid])
+ PhasingHandler::AddPhase(corpse, phaseId, false);
AddCorpse(corpse);
@@ -4111,7 +4134,7 @@ Corpse* Map::ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia /*=
bones->SetUInt32Value(CORPSE_FIELD_FLAGS, corpse->GetUInt32Value(CORPSE_FIELD_FLAGS) | CORPSE_FLAG_BONES);
- bones->CopyPhaseFrom(corpse);
+ PhasingHandler::InheritPhaseShift(bones, corpse);
AddCorpse(bones);
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 03f5f1bb6e6..ee43874fe2c 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -48,6 +48,7 @@ class InstanceScript;
class InstanceScenario;
class MapInstanced;
class Object;
+class PhaseShift;
class Player;
class TempSummon;
class Unit;
@@ -487,14 +488,14 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
BattlegroundMap* ToBattlegroundMap() { if (IsBattlegroundOrArena()) return reinterpret_cast<BattlegroundMap*>(this); else return NULL; }
BattlegroundMap const* ToBattlegroundMap() const { if (IsBattlegroundOrArena()) return reinterpret_cast<BattlegroundMap const*>(this); return NULL; }
- float GetWaterOrGroundLevel(std::set<uint32> const& phases, float x, float y, float z, float* ground = nullptr, bool swim = false) const;
- float GetHeight(std::set<uint32> const& phases, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
- bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, std::set<uint32> const& phases) const;
+ float GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground = nullptr, bool swim = false) const;
+ float GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
+ bool isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2) const;
void Balance() { _dynamicTree.balance(); }
void RemoveGameObjectModel(const GameObjectModel& model) { _dynamicTree.remove(model); }
void InsertGameObjectModel(const GameObjectModel& model) { _dynamicTree.insert(model); }
bool ContainsGameObjectModel(const GameObjectModel& model) const { return _dynamicTree.contains(model);}
- bool getObjectHitPos(std::set<uint32> const& phases, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float modifyDist);
+ bool getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float modifyDist);
virtual ObjectGuid::LowType GetOwnerGuildId(uint32 /*team*/ = TEAM_OTHER) const { return UI64LIT(0); }
/*
@@ -537,7 +538,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
void SendInitTransports(Player* player);
void SendRemoveTransports(Player* player);
- void SendUpdateTransportVisibility(Player* player, std::set<uint32> const& previousPhases);
+ void SendUpdateTransportVisibility(Player* player);
void SendZoneDynamicInfo(uint32 zoneId, Player* player) const;
void SendZoneWeather(uint32 zoneId, Player* player) const;
void SendZoneWeather(ZoneDynamicInfo const& zoneDynamicInfo, Player* player) const;
diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp
index 9980a72dfb8..8435b86ecae 100644
--- a/src/server/game/Maps/TransportMgr.cpp
+++ b/src/server/game/Maps/TransportMgr.cpp
@@ -23,6 +23,7 @@
#include "MoveSplineInitArgs.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "Spline.h"
#include "Transport.h"
@@ -364,7 +365,7 @@ void TransportMgr::AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg,
animNode.Path[timeSeg] = node;
}
-Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid /*= 0*/, Map* map /*= NULL*/, uint32 phaseid /*= 0*/, uint32 phasegroup /*= 0*/)
+Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid /*= 0*/, Map* map /*= nullptr*/, uint8 phaseUseFlags /*= 0*/, uint32 phaseId /*= 0*/, uint32 phaseGroupId /*= 0*/)
{
// instance case, execute GetGameObjectEntry hook
if (map)
@@ -404,12 +405,7 @@ Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid
return NULL;
}
- if (phaseid)
- trans->SetInPhase(phaseid, false, true);
-
- if (phasegroup)
- for (auto ph : sDB2Manager.GetPhasesForGroup(phasegroup))
- trans->SetInPhase(ph, false, true);
+ PhasingHandler::InitDbPhaseShift(trans->GetPhaseShift(), phaseUseFlags, phaseId, phaseGroupId);
if (MapEntry const* mapEntry = sMapStore.LookupEntry(mapId))
{
@@ -439,7 +435,7 @@ void TransportMgr::SpawnContinentTransports()
uint32 oldMSTime = getMSTime();
- QueryResult result = WorldDatabase.Query("SELECT guid, entry, phaseid, phasegroup FROM transports");
+ QueryResult result = WorldDatabase.Query("SELECT guid, entry, phaseUseFlags, phaseid, phasegroup FROM transports");
uint32 count = 0;
if (result)
@@ -449,12 +445,50 @@ void TransportMgr::SpawnContinentTransports()
Field* fields = result->Fetch();
ObjectGuid::LowType guid = fields[0].GetUInt64();
uint32 entry = fields[1].GetUInt32();
- uint32 phaseid = fields[2].GetUInt32();
- uint32 phasegroup = fields[3].GetUInt32();
+ uint8 phaseUseFlags = fields[2].GetUInt8();
+ uint32 phaseId = fields[3].GetUInt32();
+ uint32 phaseGroupId = fields[4].GetUInt32();
+
+ if (phaseUseFlags & ~PHASE_USE_FLAGS_ALL)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) with unknown `phaseUseFlags` set, removed unknown value.", guid, entry);
+ phaseUseFlags &= PHASE_USE_FLAGS_ALL;
+ }
+
+ if (phaseUseFlags & PHASE_USE_FLAGS_ALWAYS_VISIBLE && phaseUseFlags & PHASE_USE_FLAGS_INVERSE)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE,"
+ " removing PHASE_USE_FLAGS_INVERSE.", guid, entry);
+ phaseUseFlags &= ~PHASE_USE_FLAGS_INVERSE;
+ }
+
+ if (phaseGroupId && phaseId)
+ {
+ TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, entry);
+ phaseGroupId = 0;
+ }
+
+ if (phaseId)
+ {
+ if (!sPhaseStore.LookupEntry(phaseId))
+ {
+ TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) with `phaseid` %u does not exist, set to 0", guid, entry, phaseId);
+ phaseId = 0;
+ }
+ }
+
+ if (phaseGroupId)
+ {
+ if (!sDB2Manager.GetPhasesForGroup(phaseGroupId))
+ {
+ TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) with `phaseGroup` %u does not exist, set to 0", guid, entry, phaseGroupId);
+ phaseGroupId = 0;
+ }
+ }
if (TransportTemplate const* tInfo = GetTransportTemplate(entry))
if (!tInfo->inInstance)
- if (CreateTransport(entry, guid, nullptr, phaseid, phasegroup))
+ if (CreateTransport(entry, guid, nullptr, phaseUseFlags, phaseId, phaseGroupId))
++count;
} while (result->NextRow());
diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h
index 902052200aa..aca00038205 100644
--- a/src/server/game/Maps/TransportMgr.h
+++ b/src/server/game/Maps/TransportMgr.h
@@ -114,7 +114,7 @@ class TC_GAME_API TransportMgr
void LoadTransportAnimationAndRotation();
// Creates a transport using given GameObject template entry
- Transport* CreateTransport(uint32 entry, ObjectGuid::LowType guid = UI64LIT(0), Map* map = nullptr, uint32 phaseid = 0, uint32 phasegroup = 0);
+ Transport* CreateTransport(uint32 entry, ObjectGuid::LowType guid = UI64LIT(0), Map* map = nullptr, uint8 phaseUseFlags = 0, uint32 phaseId = 0, uint32 phaseGroupId = 0);
// Spawns all continent transports, used at core startup
void SpawnContinentTransports();
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 8f8c8ab8d92..0f4135cad3a 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -212,16 +212,16 @@ enum TrinityStrings
LANG_LIQUID_STATUS = 175,
LANG_INVALID_GAMEOBJECT_TYPE = 176,
LANG_GAMEOBJECT_DAMAGED = 177,
+ LANG_GRID_POSITION = 178,
- LANG_PHASING_SUCCESS = 178,
- LANG_PHASING_FAILED = 179,
- LANG_PHASING_LAST_PHASE = 180,
- LANG_PHASING_LIST = 181,
- LANG_PHASING_PHASEMASK = 182,
- LANG_PHASING_REPORT_STATUS = 183,
- LANG_PHASING_NO_DEFINITIONS = 184, // Phasing
+ LANG_PHASESHIFT_STATUS = 179,
+ LANG_PHASESHIFT_PHASES = 180,
+ LANG_PHASESHIFT_VISIBLE_MAP_IDS = 181,
+ LANG_PHASESHIFT_UI_WORLD_MAP_AREA_SWAPS = 182,
+ LANG_PHASE_FLAG_COSMETIC = 183,
+ LANG_PHASE_FLAG_PERSONAL = 184,
- LANG_GRID_POSITION = 185,
+ // 185 not used
LANG_TRANSPORT_POSITION = 186,
// Room for more level 1 187-199 not used
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
index 98e8863ee99..6d2c336cbc3 100644
--- a/src/server/game/Movement/MotionMaster.cpp
+++ b/src/server/game/Movement/MotionMaster.cpp
@@ -506,7 +506,7 @@ void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool
if (_owner->IsFlying())
point.z = z;
else
- point.z = _owner->GetMap()->GetHeight(_owner->GetPhases(), point.x, point.y, z);
+ point.z = _owner->GetMap()->GetHeight(_owner->GetPhaseShift(), point.x, point.y, z);
init.Path().push_back(point);
}
@@ -589,7 +589,7 @@ void MotionMaster::ResumeSplineChain(SplineChainResumeInfo const& info)
void MotionMaster::MoveFall(uint32 id /*=0*/)
{
// use larger distance for vmap height search than in most other cases
- float tz = _owner->GetMap()->GetHeight(_owner->GetPhases(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ(), true, MAX_FALL_DISTANCE);
+ float tz = _owner->GetMap()->GetHeight(_owner->GetPhaseShift(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ(), true, MAX_FALL_DISTANCE);
if (tz <= INVALID_HEIGHT)
{
TC_LOG_DEBUG("misc", "MotionMaster::MoveFall: unable to retrieve a proper height at map %u (x: %f, y: %f, z: %f).",
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
index 46443db4aa6..6603aeade68 100644
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
@@ -64,7 +64,7 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)
// Limit height change
const float distanceZ = float(rand_norm()) * travelDistZ/2.0f;
destZ = respZ + distanceZ;
- float levelZ = map->GetWaterOrGroundLevel(creature->GetPhases(), destX, destY, destZ-2.5f);
+ float levelZ = map->GetWaterOrGroundLevel(creature->GetPhaseShift(), destX, destY, destZ-2.5f);
// Problem here, we must fly above the ground and water, not under. Let's try on next tick
if (levelZ >= destZ)
@@ -78,17 +78,17 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)
// The fastest way to get an accurate result 90% of the time.
// Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
- destZ = map->GetHeight(creature->GetPhases(), destX, destY, respZ+travelDistZ-2.0f, false);
+ destZ = map->GetHeight(creature->GetPhaseShift(), destX, destY, respZ+travelDistZ-2.0f, false);
if (std::fabs(destZ - respZ) > travelDistZ) // Map check
{
// Vmap Horizontal or above
- destZ = map->GetHeight(creature->GetPhases(), destX, destY, respZ - 2.0f, true);
+ destZ = map->GetHeight(creature->GetPhaseShift(), destX, destY, respZ - 2.0f, true);
if (std::fabs(destZ - respZ) > travelDistZ)
{
// Vmap Higher
- destZ = map->GetHeight(creature->GetPhases(), destX, destY, respZ+travelDistZ-2.0f, true);
+ destZ = map->GetHeight(creature->GetPhaseShift(), destX, destY, respZ+travelDistZ-2.0f, true);
// let's forget this bad coords where a z cannot be find and retry at next tick
if (std::fabs(destZ - respZ) > travelDistZ)
diff --git a/src/server/game/Phasing/PhaseShift.cpp b/src/server/game/Phasing/PhaseShift.cpp
new file mode 100644
index 00000000000..b2885ae15bb
--- /dev/null
+++ b/src/server/game/Phasing/PhaseShift.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "PhaseShift.h"
+#include "Containers.h"
+
+bool PhaseShift::AddPhase(uint32 phaseId, PhaseFlags flags, std::vector<Condition*> const* areaConditions, int32 references /*= 1*/)
+{
+ auto insertResult = Phases.emplace(phaseId, flags, nullptr);
+ ModifyPhasesReferences(insertResult.first, references);
+ if (areaConditions)
+ insertResult.first->AreaConditions = areaConditions;
+
+ return insertResult.second;
+}
+
+PhaseShift::EraseResult<PhaseShift::PhaseContainer> PhaseShift::RemovePhase(uint32 phaseId)
+{
+ auto itr = Phases.find(PhaseRef(phaseId, PhaseFlags::None, nullptr));
+ if (itr != Phases.end())
+ {
+ ModifyPhasesReferences(itr, -1);
+ if (!itr->References)
+ return { Phases.erase(itr), true };
+ return { itr, false };
+ }
+ return { Phases.end(), false };
+}
+
+bool PhaseShift::AddVisibleMapId(uint32 visibleMapId, TerrainSwapInfo const* visibleMapInfo, int32 references /*= 1*/)
+{
+ auto insertResult = VisibleMapIds.emplace(visibleMapId, VisibleMapIdRef{ 0, visibleMapInfo });
+ insertResult.first->second.References += references;
+ return insertResult.second;
+}
+
+PhaseShift::EraseResult<PhaseShift::VisibleMapIdContainer> PhaseShift::RemoveVisibleMapId(uint32 visibleMapId)
+{
+ auto itr = VisibleMapIds.find(visibleMapId);
+ if (itr != VisibleMapIds.end())
+ {
+ if (!--itr->second.References)
+ return { VisibleMapIds.erase(itr), true };
+ return { itr, false };
+ }
+ return { VisibleMapIds.end(), false };
+}
+
+bool PhaseShift::AddUiWorldMapAreaIdSwap(uint32 uiWorldMapAreaId, int32 references /*= 1*/)
+{
+ auto insertResult = UiWorldMapAreaIdSwaps.emplace(uiWorldMapAreaId, UiWorldMapAreaIdSwapRef{ 0 });
+ insertResult.first->second.References += references;
+ return insertResult.second;
+}
+
+PhaseShift::EraseResult<PhaseShift::UiWorldMapAreaIdSwapContainer> PhaseShift::RemoveUiWorldMapAreaIdSwap(uint32 uiWorldMapAreaId)
+{
+ auto itr = UiWorldMapAreaIdSwaps.find(uiWorldMapAreaId);
+ if (itr != UiWorldMapAreaIdSwaps.end())
+ {
+ if (!--itr->second.References)
+ return { UiWorldMapAreaIdSwaps.erase(itr), true };
+ return { itr, false };
+ }
+ return { UiWorldMapAreaIdSwaps.end(), false };
+}
+
+void PhaseShift::Clear()
+{
+ ClearPhases();
+ PersonalGuid.Clear();
+ VisibleMapIds.clear();
+ UiWorldMapAreaIdSwaps.clear();
+}
+
+void PhaseShift::ClearPhases()
+{
+ Flags &= EnumClassFlag<PhaseShiftFlags>(PhaseShiftFlags::AlwaysVisible) | PhaseShiftFlags::Inverse;
+ Phases.clear();
+ NonCosmeticReferences = 0;
+ CosmeticReferences = 0;
+ DefaultReferences = 0;
+ UpdateUnphasedFlag();
+}
+
+bool PhaseShift::CanSee(PhaseShift const& other) const
+{
+ if (Flags.HasFlag(PhaseShiftFlags::Unphased) && other.Flags.HasFlag(PhaseShiftFlags::Unphased))
+ return true;
+ if (Flags.HasFlag(PhaseShiftFlags::AlwaysVisible) || other.Flags.HasFlag(PhaseShiftFlags::AlwaysVisible))
+ return true;
+ if (Flags.HasFlag(PhaseShiftFlags::Inverse) && other.Flags.HasFlag(PhaseShiftFlags::Inverse))
+ return true;
+
+ PhaseFlags excludePhasesWithFlag = PhaseFlags::None;
+ if (Flags.HasFlag(PhaseShiftFlags::NoCosmetic) && other.Flags.HasFlag(PhaseShiftFlags::NoCosmetic))
+ excludePhasesWithFlag = PhaseFlags::Cosmetic;
+
+ if (!Flags.HasFlag(PhaseShiftFlags::Inverse) && !other.Flags.HasFlag(PhaseShiftFlags::Inverse))
+ {
+ ObjectGuid ownerGuid = PersonalGuid;
+ ObjectGuid otherPersonalGuid = other.PersonalGuid;
+ return Trinity::Containers::Intersects(Phases.begin(), Phases.end(), other.Phases.begin(), other.Phases.end(),
+ [&ownerGuid, &otherPersonalGuid, excludePhasesWithFlag](PhaseRef const& myPhase, PhaseRef const& /*otherPhase*/)
+ {
+ return !myPhase.Flags.HasFlag(excludePhasesWithFlag) && (!myPhase.Flags.HasFlag(PhaseFlags::Personal) || ownerGuid == otherPersonalGuid);
+ });
+ }
+
+ auto checkInversePhaseShift = [excludePhasesWithFlag](PhaseShift const& phaseShift, PhaseShift const& excludedPhaseShift)
+ {
+ if (phaseShift.Flags.HasFlag(PhaseShiftFlags::Unphased) && !excludedPhaseShift.Flags.HasFlag(PhaseShiftFlags::InverseUnphased))
+ return true;
+
+ for (auto itr = phaseShift.Phases.begin(); itr != phaseShift.Phases.end(); ++itr)
+ {
+ if (itr->Flags.HasFlag(excludePhasesWithFlag))
+ continue;
+
+ auto itr2 = std::find(excludedPhaseShift.Phases.begin(), excludedPhaseShift.Phases.end(), *itr);
+ if (itr2 == excludedPhaseShift.Phases.end() || itr2->Flags.HasFlag(excludePhasesWithFlag))
+ return true;
+ }
+
+ return false;
+ };
+
+ if (other.Flags.HasFlag(PhaseShiftFlags::Inverse))
+ return checkInversePhaseShift(*this, other);
+
+ return checkInversePhaseShift(other, *this);
+}
+
+void PhaseShift::ModifyPhasesReferences(PhaseContainer::iterator itr, int32 references)
+{
+ itr->References += references;
+
+ if (!IsDbPhaseShift)
+ {
+ if (itr->Flags.HasFlag(PhaseFlags::Cosmetic))
+ CosmeticReferences += references;
+ else if (itr->Id != DEFAULT_PHASE)
+ NonCosmeticReferences += references;
+ else
+ DefaultReferences += references;
+
+ if (CosmeticReferences)
+ Flags |= PhaseShiftFlags::NoCosmetic;
+ else
+ Flags &= ~EnumClassFlag<PhaseShiftFlags>(PhaseShiftFlags::NoCosmetic);
+
+ UpdateUnphasedFlag();
+ }
+}
+
+void PhaseShift::UpdateUnphasedFlag()
+{
+ EnumClassFlag<PhaseShiftFlags> unphasedFlag = !Flags.HasFlag(PhaseShiftFlags::Inverse) ? PhaseShiftFlags::Unphased : PhaseShiftFlags::InverseUnphased;
+ Flags &= ~EnumClassFlag<PhaseShiftFlags>(!Flags.HasFlag(PhaseShiftFlags::Inverse) ? PhaseShiftFlags::InverseUnphased : PhaseShiftFlags::Unphased);
+ if (NonCosmeticReferences && !DefaultReferences)
+ Flags &= ~unphasedFlag;
+ else
+ Flags |= unphasedFlag;
+}
diff --git a/src/server/game/Phasing/PhaseShift.h b/src/server/game/Phasing/PhaseShift.h
new file mode 100644
index 00000000000..8755868ae9d
--- /dev/null
+++ b/src/server/game/Phasing/PhaseShift.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PhaseShift_h__
+#define PhaseShift_h__
+
+#include "Define.h"
+#include "EnumClassFlag.h"
+#include "ObjectGuid.h"
+#include <boost/container/flat_set.hpp>
+#include <map>
+
+class PhasingHandler;
+struct Condition;
+struct TerrainSwapInfo;
+
+#define DEFAULT_PHASE 169
+
+enum class PhaseShiftFlags : uint32
+{
+ None = 0x00,
+ AlwaysVisible = 0x01, // Ignores all phasing, can see everything and be seen by everything
+ Inverse = 0x02, // By default having at least one shared phase for two objects means they can see each other
+ // this flag makes objects see each other if they have at least one non-shared phase
+ InverseUnphased = 0x04,
+ Unphased = 0x08,
+ NoCosmetic = 0x10 // This flag ignores shared cosmetic phases (two players that both have shared cosmetic phase but no other phase cannot see each other)
+};
+
+enum class PhaseFlags : uint16
+{
+ None = 0x0,
+ Cosmetic = 0x1,
+ Personal = 0x2
+};
+
+class TC_GAME_API PhaseShift
+{
+public:
+ struct PhaseRef
+ {
+ PhaseRef(uint32 id, PhaseFlags flags, std::vector<Condition*> const* conditions)
+ : Id(id), Flags(flags), References(0), AreaConditions(conditions) { }
+
+ uint16 Id;
+ EnumClassFlag<PhaseFlags> Flags;
+ int32 References;
+ std::vector<Condition*> const* AreaConditions;
+ bool operator<(PhaseRef const& right) const { return Id < right.Id; }
+ bool operator==(PhaseRef const& right) const { return Id == right.Id; }
+ };
+ struct VisibleMapIdRef
+ {
+ int32 References = 0;
+ TerrainSwapInfo const* VisibleMapInfo = nullptr;
+ };
+ struct UiWorldMapAreaIdSwapRef
+ {
+ int32 References = 0;
+ };
+ template<typename Container>
+ struct EraseResult
+ {
+ typename Container::iterator Iterator;
+ bool Erased;
+ };
+ typedef boost::container::flat_set<PhaseRef> PhaseContainer;
+ typedef std::map<uint32, VisibleMapIdRef> VisibleMapIdContainer;
+ typedef std::map<uint32, UiWorldMapAreaIdSwapRef> UiWorldMapAreaIdSwapContainer;
+
+ bool AddPhase(uint32 phaseId, PhaseFlags flags, std::vector<Condition*> const* areaConditions, int32 references = 1);
+ EraseResult<PhaseContainer> RemovePhase(uint32 phaseId);
+ bool HasPhase(uint32 phaseId) const { return Phases.find(PhaseRef(phaseId, PhaseFlags::None, nullptr)) != Phases.end(); }
+ PhaseContainer const& GetPhases() const { return Phases; }
+
+ bool AddVisibleMapId(uint32 visibleMapId, TerrainSwapInfo const* visibleMapInfo, int32 references = 1);
+ EraseResult<VisibleMapIdContainer> RemoveVisibleMapId(uint32 visibleMapId);
+ bool HasVisibleMapId(uint32 visibleMapId) const { return VisibleMapIds.find(visibleMapId) != VisibleMapIds.end(); }
+ VisibleMapIdContainer const& GetVisibleMapIds() const { return VisibleMapIds; }
+
+ bool AddUiWorldMapAreaIdSwap(uint32 uiWorldMapAreaId, int32 references = 1);
+ EraseResult<UiWorldMapAreaIdSwapContainer> RemoveUiWorldMapAreaIdSwap(uint32 uiWorldMapAreaId);
+ bool HasUiWorldMapAreaIdSwap(uint32 uiWorldMapAreaId) const { return UiWorldMapAreaIdSwaps.find(uiWorldMapAreaId) != UiWorldMapAreaIdSwaps.end(); }
+ UiWorldMapAreaIdSwapContainer const& GetUiWorldMapAreaIdSwaps() const { return UiWorldMapAreaIdSwaps; }
+
+ void Clear();
+ void ClearPhases();
+
+ bool CanSee(PhaseShift const& other) const;
+
+protected:
+ friend class PhasingHandler;
+
+ EnumClassFlag<PhaseShiftFlags> Flags = PhaseShiftFlags::Unphased;
+ ObjectGuid PersonalGuid;
+ PhaseContainer Phases;
+ VisibleMapIdContainer VisibleMapIds;
+ UiWorldMapAreaIdSwapContainer UiWorldMapAreaIdSwaps;
+
+ void ModifyPhasesReferences(PhaseContainer::iterator itr, int32 references);
+ void UpdateUnphasedFlag();
+ int32 NonCosmeticReferences = 0;
+ int32 CosmeticReferences = 0;
+ int32 DefaultReferences = 0;
+ bool IsDbPhaseShift = false;
+};
+
+#endif // PhaseShift_h__
diff --git a/src/server/game/Phasing/PhasingHandler.cpp b/src/server/game/Phasing/PhasingHandler.cpp
new file mode 100644
index 00000000000..2f0fd7d870e
--- /dev/null
+++ b/src/server/game/Phasing/PhasingHandler.cpp
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "PhasingHandler.h"
+#include "Chat.h"
+#include "ConditionMgr.h"
+#include "Creature.h"
+#include "DB2Stores.h"
+#include "Language.h"
+#include "Map.h"
+#include "MiscPackets.h"
+#include "ObjectMgr.h"
+#include "PartyPackets.h"
+#include "PhaseShift.h"
+#include "Player.h"
+#include "SpellAuraEffects.h"
+
+namespace
+{
+inline PhaseFlags GetPhaseFlags(uint32 phaseId)
+{
+ if (PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseId))
+ {
+ if (phase->Flags & PHASE_FLAG_COSMETIC)
+ return PhaseFlags::Cosmetic;
+
+ if (phase->Flags & PHASE_FLAG_PERSONAL)
+ return PhaseFlags::Personal;
+ }
+
+ return PhaseFlags::None;
+}
+
+template<typename Func>
+inline void ForAllControlled(Unit* unit, Func&& func)
+{
+ for (Unit* controlled : unit->m_Controlled)
+ if (controlled->GetTypeId() != TYPEID_PLAYER)
+ func(controlled);
+
+ for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
+ if (!unit->m_SummonSlot[i].IsEmpty())
+ if (Creature* summon = unit->GetMap()->GetCreature(unit->m_SummonSlot[i]))
+ func(summon);
+}
+}
+
+void PhasingHandler::AddPhase(WorldObject* object, uint32 phaseId, bool updateVisibility)
+{
+ bool changed = object->GetPhaseShift().AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr);
+
+ if (Unit* unit = object->ToUnit())
+ {
+ unit->OnPhaseChange();
+ ForAllControlled(unit, [&](Unit* controlled)
+ {
+ AddPhase(controlled, phaseId, updateVisibility);
+ });
+ unit->RemoveNotOwnSingleTargetAuras(true);
+ }
+
+ UpdateVisibilityIfNeeded(object, updateVisibility, changed);
+}
+
+void PhasingHandler::RemovePhase(WorldObject* object, uint32 phaseId, bool updateVisibility)
+{
+ bool changed = object->GetPhaseShift().RemovePhase(phaseId).Erased;
+
+ if (Unit* unit = object->ToUnit())
+ {
+ unit->OnPhaseChange();
+ ForAllControlled(unit, [&](Unit* controlled)
+ {
+ RemovePhase(controlled, phaseId, updateVisibility);
+ });
+ unit->RemoveNotOwnSingleTargetAuras(true);
+ }
+
+ UpdateVisibilityIfNeeded(object, updateVisibility, changed);
+}
+
+void PhasingHandler::AddPhaseGroup(WorldObject* object, uint32 phaseGroupId, bool updateVisibility)
+{
+ std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(phaseGroupId);
+ if (!phasesInGroup)
+ return;
+
+ bool changed = false;
+ for (uint32 phaseId : *phasesInGroup)
+ changed = object->GetPhaseShift().AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr) || changed;
+
+ if (Unit* unit = object->ToUnit())
+ {
+ unit->OnPhaseChange();
+ ForAllControlled(unit, [&](Unit* controlled)
+ {
+ AddPhaseGroup(controlled, phaseGroupId, updateVisibility);
+ });
+ unit->RemoveNotOwnSingleTargetAuras(true);
+ }
+
+ UpdateVisibilityIfNeeded(object, updateVisibility, changed);
+}
+
+void PhasingHandler::RemovePhaseGroup(WorldObject* object, uint32 phaseGroupId, bool updateVisibility)
+{
+ std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(phaseGroupId);
+ if (!phasesInGroup)
+ return;
+
+ bool changed = false;
+ for (uint32 phaseId : *phasesInGroup)
+ changed = object->GetPhaseShift().RemovePhase(phaseId).Erased || changed;
+
+ if (Unit* unit = object->ToUnit())
+ {
+ unit->OnPhaseChange();
+ ForAllControlled(unit, [&](Unit* controlled)
+ {
+ RemovePhaseGroup(controlled, phaseGroupId, updateVisibility);
+ });
+ unit->RemoveNotOwnSingleTargetAuras(true);
+ }
+
+ UpdateVisibilityIfNeeded(object, updateVisibility, changed);
+}
+
+void PhasingHandler::AddVisibleMapId(WorldObject* object, uint32 visibleMapId)
+{
+ TerrainSwapInfo const* terrainSwapInfo = sObjectMgr->GetTerrainSwapInfo(visibleMapId);
+ bool changed = object->GetPhaseShift().AddVisibleMapId(visibleMapId, terrainSwapInfo);
+
+ for (uint32 uiWorldMapAreaIDSwap : terrainSwapInfo->UiWorldMapAreaIDSwaps)
+ changed = object->GetPhaseShift().AddUiWorldMapAreaIdSwap(uiWorldMapAreaIDSwap) || changed;
+
+ if (Unit* unit = object->ToUnit())
+ {
+ ForAllControlled(unit, [&](Unit* controlled)
+ {
+ AddVisibleMapId(controlled, visibleMapId);
+ });
+ }
+
+ UpdateVisibilityIfNeeded(object, false, changed);
+}
+
+void PhasingHandler::RemoveVisibleMapId(WorldObject* object, uint32 visibleMapId)
+{
+ TerrainSwapInfo const* terrainSwapInfo = sObjectMgr->GetTerrainSwapInfo(visibleMapId);
+ bool changed = object->GetPhaseShift().RemoveVisibleMapId(visibleMapId).Erased;
+
+ for (uint32 uiWorldMapAreaIDSwap : terrainSwapInfo->UiWorldMapAreaIDSwaps)
+ changed = object->GetPhaseShift().RemoveUiWorldMapAreaIdSwap(uiWorldMapAreaIDSwap).Erased || changed;
+
+ if (Unit* unit = object->ToUnit())
+ {
+ ForAllControlled(unit, [&](Unit* controlled)
+ {
+ RemoveVisibleMapId(controlled, visibleMapId);
+ });
+ }
+
+ UpdateVisibilityIfNeeded(object, false, changed);
+}
+
+void PhasingHandler::ResetPhaseShift(WorldObject* object)
+{
+ object->GetPhaseShift().Clear();
+ object->GetSuppressedPhaseShift().Clear();
+}
+
+void PhasingHandler::InheritPhaseShift(WorldObject* target, WorldObject const* source)
+{
+ target->GetPhaseShift() = source->GetPhaseShift();
+ target->GetSuppressedPhaseShift() = source->GetSuppressedPhaseShift();
+}
+
+void PhasingHandler::OnMapChange(WorldObject* object)
+{
+ PhaseShift& phaseShift = object->GetPhaseShift();
+ PhaseShift& suppressedPhaseShift = object->GetSuppressedPhaseShift();
+ ConditionSourceInfo srcInfo = ConditionSourceInfo(object);
+
+ object->GetPhaseShift().VisibleMapIds.clear();
+ object->GetPhaseShift().UiWorldMapAreaIdSwaps.clear();
+ object->GetSuppressedPhaseShift().VisibleMapIds.clear();
+
+ if (std::vector<TerrainSwapInfo*> const* visibleMapIds = sObjectMgr->GetTerrainSwapsForMap(object->GetMapId()))
+ {
+ for (TerrainSwapInfo const* visibleMapInfo : *visibleMapIds)
+ {
+ if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, visibleMapInfo->Id, srcInfo))
+ {
+ phaseShift.AddVisibleMapId(visibleMapInfo->Id, visibleMapInfo);
+ for (uint32 uiWorldMapAreaIdSwap : visibleMapInfo->UiWorldMapAreaIDSwaps)
+ phaseShift.AddUiWorldMapAreaIdSwap(uiWorldMapAreaIdSwap);
+ }
+ else
+ suppressedPhaseShift.AddVisibleMapId(visibleMapInfo->Id, visibleMapInfo);
+ }
+ }
+
+ UpdateVisibilityIfNeeded(object, false, true);
+}
+
+void PhasingHandler::OnAreaChange(WorldObject* object)
+{
+ PhaseShift& phaseShift = object->GetPhaseShift();
+ PhaseShift& suppressedPhaseShift = object->GetSuppressedPhaseShift();
+ PhaseShift::PhaseContainer oldPhases = std::move(phaseShift.Phases); // for comparison
+ ConditionSourceInfo srcInfo = ConditionSourceInfo(object);
+
+ object->GetPhaseShift().ClearPhases();
+ object->GetSuppressedPhaseShift().ClearPhases();
+
+ uint32 areaId = object->GetAreaId();
+ AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
+ while (areaEntry)
+ {
+ if (std::vector<PhaseAreaInfo> const* newAreaPhases = sObjectMgr->GetPhasesForArea(areaEntry->ID))
+ {
+ for (PhaseAreaInfo const& phaseArea : *newAreaPhases)
+ {
+ if (phaseArea.SubAreaExclusions.find(areaId) != phaseArea.SubAreaExclusions.end())
+ continue;
+
+ uint32 phaseId = phaseArea.PhaseInfo->Id;
+ if (sConditionMgr->IsObjectMeetToConditions(srcInfo, phaseArea.Conditions))
+ phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), &phaseArea.Conditions);
+ else
+ suppressedPhaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), &phaseArea.Conditions);
+ }
+ }
+
+ areaEntry = sAreaTableStore.LookupEntry(areaEntry->ParentAreaID);
+ }
+
+ bool changed = phaseShift.Phases != oldPhases;
+ if (Unit* unit = object->ToUnit())
+ {
+ for (AuraEffect const* aurEff : unit->GetAuraEffectsByType(SPELL_AURA_PHASE))
+ {
+ uint32 phaseId = uint32(aurEff->GetMiscValueB());
+ changed = phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr) || changed;
+ }
+
+ for (AuraEffect const* aurEff : unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP))
+ if (std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(uint32(aurEff->GetMiscValueB())))
+ for (uint32 phaseId : *phasesInGroup)
+ changed = phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr) || changed;
+
+ if (changed)
+ unit->OnPhaseChange();
+
+ ForAllControlled(unit, [&](Unit* controlled)
+ {
+ InheritPhaseShift(controlled, unit);
+ });
+
+ if (changed)
+ unit->RemoveNotOwnSingleTargetAuras(true);
+ }
+
+ UpdateVisibilityIfNeeded(object, true, changed);
+}
+
+void PhasingHandler::OnConditionChange(WorldObject* object)
+{
+ PhaseShift& phaseShift = object->GetPhaseShift();
+ PhaseShift& suppressedPhaseShift = object->GetSuppressedPhaseShift();
+ PhaseShift newSuppressions;
+ ConditionSourceInfo srcInfo = ConditionSourceInfo(object);
+ bool changed = false;
+
+ for (auto itr = phaseShift.Phases.begin(); itr != phaseShift.Phases.end();)
+ {
+ if (itr->AreaConditions && !sConditionMgr->IsObjectMeetToConditions(srcInfo, *itr->AreaConditions))
+ {
+ newSuppressions.AddPhase(itr->Id, itr->Flags, itr->AreaConditions, itr->References);
+ itr = phaseShift.Phases.erase(itr);
+ }
+ else
+ ++itr;
+ }
+
+ for (auto itr = suppressedPhaseShift.Phases.begin(); itr != suppressedPhaseShift.Phases.end();)
+ {
+ if (sConditionMgr->IsObjectMeetToConditions(srcInfo, *ASSERT_NOTNULL(itr->AreaConditions)))
+ {
+ changed = phaseShift.AddPhase(itr->Id, itr->Flags, itr->AreaConditions, itr->References) || changed;
+ itr = suppressedPhaseShift.Phases.erase(itr);
+ }
+ else
+ ++itr;
+ }
+
+ for (auto itr = phaseShift.VisibleMapIds.begin(); itr != phaseShift.VisibleMapIds.end();)
+ {
+ if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, itr->first, srcInfo))
+ {
+ newSuppressions.AddVisibleMapId(itr->first, itr->second.VisibleMapInfo, itr->second.References);
+ for (uint32 uiWorldMapAreaIdSwap : itr->second.VisibleMapInfo->UiWorldMapAreaIDSwaps)
+ changed = phaseShift.RemoveUiWorldMapAreaIdSwap(uiWorldMapAreaIdSwap).Erased || changed;
+
+ itr = phaseShift.VisibleMapIds.erase(itr);
+ }
+ else
+ ++itr;
+ }
+
+ for (auto itr = suppressedPhaseShift.VisibleMapIds.begin(); itr != suppressedPhaseShift.VisibleMapIds.end();)
+ {
+ if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, itr->first, srcInfo))
+ {
+ changed = phaseShift.AddVisibleMapId(itr->first, itr->second.VisibleMapInfo, itr->second.References) || changed;
+ for (uint32 uiWorldMapAreaIdSwap : itr->second.VisibleMapInfo->UiWorldMapAreaIDSwaps)
+ changed = phaseShift.AddUiWorldMapAreaIdSwap(uiWorldMapAreaIdSwap) || changed;
+
+ itr = suppressedPhaseShift.VisibleMapIds.erase(itr);
+ }
+ else
+ ++itr;
+ }
+
+ Unit* unit = object->ToUnit();
+ if (unit)
+ {
+ for (AuraEffect const* aurEff : unit->GetAuraEffectsByType(SPELL_AURA_PHASE))
+ {
+ uint32 phaseId = uint32(aurEff->GetMiscValueB());
+ auto eraseResult = newSuppressions.RemovePhase(phaseId);
+ // if condition was met previously there is nothing to erase
+ if (eraseResult.Iterator != newSuppressions.Phases.end() || eraseResult.Erased)
+ phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr);
+ }
+
+ for (AuraEffect const* aurEff : unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP))
+ {
+ if (std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(uint32(aurEff->GetMiscValueB())))
+ {
+ for (uint32 phaseId : *phasesInGroup)
+ {
+ auto eraseResult = newSuppressions.RemovePhase(phaseId);
+ // if condition was met previously there is nothing to erase
+ if (eraseResult.Iterator != newSuppressions.Phases.end() || eraseResult.Erased)
+ phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr);
+ }
+ }
+ }
+ }
+
+ changed = changed || !newSuppressions.Phases.empty() || !newSuppressions.VisibleMapIds.empty();
+ for (auto itr = newSuppressions.Phases.begin(); itr != newSuppressions.Phases.end(); ++itr)
+ suppressedPhaseShift.AddPhase(itr->Id, itr->Flags, itr->AreaConditions, itr->References);
+
+ for (auto itr = newSuppressions.VisibleMapIds.begin(); itr != newSuppressions.VisibleMapIds.end(); ++itr)
+ suppressedPhaseShift.AddVisibleMapId(itr->first, itr->second.VisibleMapInfo, itr->second.References);
+
+ if (unit)
+ {
+ if (changed)
+ unit->OnPhaseChange();
+
+ ForAllControlled(unit, [&](Unit* controlled)
+ {
+ InheritPhaseShift(controlled, unit);
+ });
+
+ if (changed)
+ unit->RemoveNotOwnSingleTargetAuras(true);
+ }
+
+ UpdateVisibilityIfNeeded(object, true, changed);
+}
+
+void PhasingHandler::SendToPlayer(Player const* player, PhaseShift const& phaseShift)
+{
+ WorldPackets::Misc::PhaseShiftChange phaseShiftChange;
+ phaseShiftChange.Client = player->GetGUID();
+ phaseShiftChange.Phaseshift.PhaseShiftFlags = phaseShift.Flags.AsUnderlyingType();
+ phaseShiftChange.Phaseshift.PersonalGUID = phaseShift.PersonalGuid;
+ phaseShiftChange.Phaseshift.Phases.reserve(phaseShift.Phases.size());
+ std::transform(phaseShift.Phases.begin(), phaseShift.Phases.end(), std::back_inserter(phaseShiftChange.Phaseshift.Phases),
+ [](PhaseShift::PhaseRef const& phase) -> WorldPackets::Misc::PhaseShiftDataPhase { return { phase.Flags.AsUnderlyingType(), phase.Id }; });
+ phaseShiftChange.VisibleMapIDs.reserve(phaseShift.VisibleMapIds.size());
+ std::transform(phaseShift.VisibleMapIds.begin(), phaseShift.VisibleMapIds.end(), std::back_inserter(phaseShiftChange.VisibleMapIDs),
+ [](PhaseShift::VisibleMapIdContainer::value_type const& visibleMapId) { return visibleMapId.first; });
+ phaseShiftChange.UiWorldMapAreaIDSwaps.reserve(phaseShift.UiWorldMapAreaIdSwaps.size());
+ std::transform(phaseShift.UiWorldMapAreaIdSwaps.begin(), phaseShift.UiWorldMapAreaIdSwaps.end(), std::back_inserter(phaseShiftChange.UiWorldMapAreaIDSwaps),
+ [](PhaseShift::UiWorldMapAreaIdSwapContainer::value_type const& uiWorldMapAreaIdSwap) { return uiWorldMapAreaIdSwap.first; });
+
+ player->SendDirectMessage(phaseShiftChange.Write());
+}
+
+void PhasingHandler::SendToPlayer(Player const* player)
+{
+ SendToPlayer(player, player->GetPhaseShift());
+}
+
+void PhasingHandler::FillPartyMemberPhase(WorldPackets::Party::PartyMemberPhaseStates* partyMemberPhases, PhaseShift const& phaseShift)
+{
+ partyMemberPhases->PhaseShiftFlags = phaseShift.Flags.AsUnderlyingType();
+ partyMemberPhases->PersonalGUID = phaseShift.PersonalGuid;
+ partyMemberPhases->List.reserve(phaseShift.Phases.size());
+ std::transform(phaseShift.Phases.begin(), phaseShift.Phases.end(), std::back_inserter(partyMemberPhases->List),
+ [](PhaseShift::PhaseRef const& phase) -> WorldPackets::Party::PartyMemberPhase { return { phase.Flags.AsUnderlyingType(), phase.Id }; });
+}
+
+void PhasingHandler::InitDbPhaseShift(PhaseShift& phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId)
+{
+ phaseShift.IsDbPhaseShift = true;
+
+ EnumClassFlag<PhaseShiftFlags> flags = PhaseShiftFlags::None;
+ if (phaseUseFlags & PHASE_USE_FLAGS_ALWAYS_VISIBLE)
+ flags = flags | PhaseShiftFlags::AlwaysVisible | PhaseShiftFlags::Unphased;
+ if (phaseUseFlags & PHASE_USE_FLAGS_INVERSE)
+ flags |= PhaseShiftFlags::Inverse;
+
+ if (phaseId)
+ phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr);
+ else if (std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(phaseGroupId))
+ for (uint32 phaseInGroup : *phasesInGroup)
+ phaseShift.AddPhase(phaseInGroup, GetPhaseFlags(phaseInGroup), nullptr);
+
+ if (phaseShift.Phases.empty() || phaseShift.HasPhase(DEFAULT_PHASE))
+ {
+ if (flags.HasFlag(PhaseShiftFlags::Inverse))
+ flags |= PhaseShiftFlags::InverseUnphased;
+ else
+ flags |= PhaseShiftFlags::Unphased;
+ }
+
+ phaseShift.Flags = flags;
+}
+
+void PhasingHandler::InitDbVisibleMapId(PhaseShift& phaseShift, int32 visibleMapId)
+{
+ if (visibleMapId != -1)
+ phaseShift.AddVisibleMapId(visibleMapId, sObjectMgr->GetTerrainSwapInfo(visibleMapId));
+}
+
+bool PhasingHandler::InDbPhaseShift(WorldObject const* object, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId)
+{
+ PhaseShift phaseShift;
+ InitDbPhaseShift(phaseShift, phaseUseFlags, phaseId, phaseGroupId);
+ return object->GetPhaseShift().CanSee(phaseShift);
+}
+
+void PhasingHandler::SetAlwaysVisible(PhaseShift& phaseShift, bool apply)
+{
+ if (apply)
+ phaseShift.Flags |= PhaseShiftFlags::AlwaysVisible;
+ else
+ phaseShift.Flags &= ~EnumClassFlag<PhaseShiftFlags>(PhaseShiftFlags::AlwaysVisible);
+}
+
+void PhasingHandler::SetInversed(PhaseShift& phaseShift, bool apply)
+{
+ if (apply)
+ phaseShift.Flags |= PhaseShiftFlags::Inverse;
+ else
+ phaseShift.Flags &= ~EnumClassFlag<PhaseShiftFlags>(PhaseShiftFlags::Inverse);
+
+ phaseShift.UpdateUnphasedFlag();
+}
+
+void PhasingHandler::PrintToChat(ChatHandler* chat, PhaseShift const& phaseShift)
+{
+ chat->PSendSysMessage(LANG_PHASESHIFT_STATUS, phaseShift.Flags.AsUnderlyingType(), phaseShift.PersonalGuid.ToString().c_str());
+ if (!phaseShift.Phases.empty())
+ {
+ std::ostringstream phases;
+ std::string cosmetic = sObjectMgr->GetTrinityString(LANG_PHASE_FLAG_COSMETIC, chat->GetSessionDbLocaleIndex());
+ std::string personal = sObjectMgr->GetTrinityString(LANG_PHASE_FLAG_PERSONAL, chat->GetSessionDbLocaleIndex());
+ for (PhaseShift::PhaseRef const& phase : phaseShift.Phases)
+ {
+ phases << phase.Id;
+ if (phase.Flags.HasFlag(PhaseFlags::Cosmetic))
+ phases << ' ' << '(' << cosmetic << ')';
+ if (phase.Flags.HasFlag(PhaseFlags::Personal))
+ phases << ' ' << '(' << personal << ')';
+ phases << ", ";
+ }
+
+ chat->PSendSysMessage(LANG_PHASESHIFT_PHASES, phases.str().c_str());
+ }
+
+ if (!phaseShift.VisibleMapIds.empty())
+ {
+ std::ostringstream visibleMapIds;
+ for (PhaseShift::VisibleMapIdContainer::value_type const& visibleMapId : phaseShift.VisibleMapIds)
+ visibleMapIds << visibleMapId.first << ',' << ' ';
+
+ chat->PSendSysMessage(LANG_PHASESHIFT_VISIBLE_MAP_IDS, visibleMapIds.str().c_str());
+ }
+
+ if (!phaseShift.UiWorldMapAreaIdSwaps.empty())
+ {
+ std::ostringstream uiWorldMapAreaIdSwaps;
+ for (PhaseShift::UiWorldMapAreaIdSwapContainer::value_type const& uiWorldMapAreaIdSwap : phaseShift.UiWorldMapAreaIdSwaps)
+ uiWorldMapAreaIdSwaps << uiWorldMapAreaIdSwap.first << ',' << ' ';
+
+ chat->PSendSysMessage(LANG_PHASESHIFT_UI_WORLD_MAP_AREA_SWAPS, uiWorldMapAreaIdSwaps.str().c_str());
+ }
+}
+
+std::string PhasingHandler::FormatPhases(PhaseShift const& phaseShift)
+{
+ std::ostringstream phases;
+ for (PhaseShift::PhaseRef const& phase : phaseShift.Phases)
+ phases << phase.Id << ',';
+
+ return phases.str();
+}
+
+void PhasingHandler::UpdateVisibilityIfNeeded(WorldObject* object, bool updateVisibility, bool changed)
+{
+ if (changed && object->IsInWorld())
+ {
+ if (Player* player = object->ToPlayer())
+ SendToPlayer(player);
+
+ if (updateVisibility)
+ {
+ if (Player* player = object->ToPlayer())
+ player->GetMap()->SendUpdateTransportVisibility(player);
+
+ object->UpdateObjectVisibility();
+ }
+ }
+}
diff --git a/src/server/game/Phasing/PhasingHandler.h b/src/server/game/Phasing/PhasingHandler.h
new file mode 100644
index 00000000000..e759f2e68e1
--- /dev/null
+++ b/src/server/game/Phasing/PhasingHandler.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PhasingHandler_h__
+#define PhasingHandler_h__
+
+#include "Define.h"
+#include <string>
+
+class ChatHandler;
+class PhaseShift;
+class Player;
+class WorldObject;
+namespace WorldPackets
+{
+ namespace Party
+ {
+ struct PartyMemberPhaseStates;
+ }
+}
+
+class TC_GAME_API PhasingHandler
+{
+public:
+ static void AddPhase(WorldObject* object, uint32 phaseId, bool updateVisibility);
+ static void RemovePhase(WorldObject* object, uint32 phaseId, bool updateVisibility);
+ static void AddPhaseGroup(WorldObject* object, uint32 phaseGroupId, bool updateVisibility);
+ static void RemovePhaseGroup(WorldObject* object, uint32 phaseGroupId, bool updateVisibility);
+
+ static void AddVisibleMapId(WorldObject* object, uint32 visibleMapId);
+ static void RemoveVisibleMapId(WorldObject* object, uint32 visibleMapId);
+
+ static void ResetPhaseShift(WorldObject* object);
+ static void InheritPhaseShift(WorldObject* target, WorldObject const* source);
+
+ static void OnMapChange(WorldObject* object);
+ static void OnAreaChange(WorldObject* object);
+ static void OnConditionChange(WorldObject* object);
+
+ static void SendToPlayer(Player const* player, PhaseShift const& phaseShift);
+ static void SendToPlayer(Player const* player);
+ static void FillPartyMemberPhase(WorldPackets::Party::PartyMemberPhaseStates* partyMemberPhases, PhaseShift const& phaseShift);
+
+ static void InitDbPhaseShift(PhaseShift& phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId);
+ static void InitDbVisibleMapId(PhaseShift& phaseShift, int32 visibleMapId);
+ static bool InDbPhaseShift(WorldObject const* object, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId);
+
+ static void SetAlwaysVisible(PhaseShift& phaseShift, bool apply);
+ static void SetInversed(PhaseShift& phaseShift, bool apply);
+
+ static void PrintToChat(ChatHandler* chat, PhaseShift const& phaseShift);
+ static std::string FormatPhases(PhaseShift const& phaseShift);
+
+private:
+ static void UpdateVisibilityIfNeeded(WorldObject* object, bool updateVisibility, bool changed);
+};
+
+#endif // PhasingHandler_h__
diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp
index e5795b6b7f4..a03f1ff35fc 100644
--- a/src/server/game/Server/Packets/MiscPackets.cpp
+++ b/src/server/game/Server/Packets/MiscPackets.cpp
@@ -376,29 +376,39 @@ WorldPacket const* WorldPackets::Misc::RandomRoll::Write()
return &_worldPacket;
}
-WorldPacket const* WorldPackets::Misc::PhaseShift::Write()
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Misc::PhaseShiftDataPhase const& phaseShiftDataPhase)
{
- _worldPacket << ClientGUID; // CLientGUID
- _worldPacket << uint32(PhaseShifts.size() ? 0 : 8); // PhaseShiftFlags
- _worldPacket << uint32(PhaseShifts.size()); // PhaseShiftCount
- _worldPacket << PersonalGUID; // PersonalGUID
- for (uint32 phase : PhaseShifts)
- {
- _worldPacket << uint16(1); // PhaseFlags
- _worldPacket << uint16(phase); // PhaseID
- }
+ data << uint16(phaseShiftDataPhase.PhaseFlags);
+ data << uint16(phaseShiftDataPhase.Id);
+ return data;
+}
+
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Misc::PhaseShiftData const& phaseShiftData)
+{
+ data << uint32(phaseShiftData.PhaseShiftFlags);
+ data << uint32(phaseShiftData.Phases.size());
+ data << phaseShiftData.PersonalGUID;
+ for (WorldPackets::Misc::PhaseShiftDataPhase const& phaseShiftDataPhase : phaseShiftData.Phases)
+ data << phaseShiftDataPhase;
+
+ return data;
+}
- _worldPacket << uint32(VisibleMapIDs.size() * 2); // Active terrain swaps size
- for (uint32 map : VisibleMapIDs)
- _worldPacket << uint16(map); // Active terrain swap map id
+WorldPacket const* WorldPackets::Misc::PhaseShiftChange::Write()
+{
+ _worldPacket << Client;
+ _worldPacket << Phaseshift;
+ _worldPacket << uint32(VisibleMapIDs.size() * 2); // size in bytes
+ for (uint16 visibleMapId : VisibleMapIDs)
+ _worldPacket << uint16(visibleMapId); // Active terrain swap map id
- _worldPacket << uint32(PreloadMapIDs.size() * 2); // Inactive terrain swaps size
- for (uint32 map : PreloadMapIDs)
- _worldPacket << uint16(map); // Inactive terrain swap map id
+ _worldPacket << uint32(PreloadMapIDs.size() * 2); // size in bytes
+ for (uint16 preloadMapId : PreloadMapIDs)
+ _worldPacket << uint16(preloadMapId); // Inactive terrain swap map id
- _worldPacket << uint32(UiWorldMapAreaIDSwaps.size() * 2); // UI map swaps size
- for (uint32 map : UiWorldMapAreaIDSwaps)
- _worldPacket << uint16(map); // UI map id, WorldMapArea.dbc, controls map display
+ _worldPacket << uint32(UiWorldMapAreaIDSwaps.size() * 2); // size in bytes
+ for (uint16 uiWorldMapAreaIDSwap : UiWorldMapAreaIDSwaps)
+ _worldPacket << uint16(uiWorldMapAreaIDSwap); // UI map id, WorldMapArea.db2, controls map display
return &_worldPacket;
}
diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h
index e875885864f..26affbaf934 100644
--- a/src/server/game/Server/Packets/MiscPackets.h
+++ b/src/server/game/Server/Packets/MiscPackets.h
@@ -28,7 +28,6 @@
#include "SharedDefines.h"
#include <array>
#include <map>
-#include <set>
enum MountStatusFlags : uint8;
enum UnitStandStateType : uint8;
@@ -529,19 +528,31 @@ namespace WorldPackets
WorldPacket const* Write() override { return &_worldPacket; }
};
- class PhaseShift final : public ServerPacket
+ struct PhaseShiftDataPhase
+ {
+ uint16 PhaseFlags = 0;
+ uint16 Id = 0;
+ };
+
+ struct PhaseShiftData
+ {
+ uint32 PhaseShiftFlags = 0;
+ std::vector<PhaseShiftDataPhase> Phases;
+ ObjectGuid PersonalGUID;
+ };
+
+ class PhaseShiftChange final : public ServerPacket
{
public:
- PhaseShift() : ServerPacket(SMSG_PHASE_SHIFT_CHANGE, 4) { }
+ PhaseShiftChange() : ServerPacket(SMSG_PHASE_SHIFT_CHANGE, 16 + 4 + 4 + 16 + 4 + 4 + 4) { }
WorldPacket const* Write() override;
- ObjectGuid ClientGUID;
- ObjectGuid PersonalGUID;
- std::set<uint32> PhaseShifts;
- std::set<uint32> PreloadMapIDs;
- std::set<uint32> UiWorldMapAreaIDSwaps;
- std::set<uint32> VisibleMapIDs;
+ ObjectGuid Client;
+ PhaseShiftData Phaseshift;
+ std::vector<uint16> PreloadMapIDs;
+ std::vector<uint16> UiWorldMapAreaIDSwaps;
+ std::vector<uint16> VisibleMapIDs;
};
class ZoneUnderAttack final : public ServerPacket
diff --git a/src/server/game/Server/Packets/PartyPackets.cpp b/src/server/game/Server/Packets/PartyPackets.cpp
index d3d1f45995d..939f0a65db1 100644
--- a/src/server/game/Server/Packets/PartyPackets.cpp
+++ b/src/server/game/Server/Packets/PartyPackets.cpp
@@ -17,6 +17,7 @@
#include "PartyPackets.h"
#include "Pet.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "Realm.h"
#include "SpellAuraEffects.h"
@@ -625,16 +626,7 @@ void WorldPackets::Party::PartyMemberState::Initialize(Player const* player)
}
// Phases
- std::set<uint32> const& phases = player->GetPhases();
- MemberStats.Phases.PhaseShiftFlags = 0x08 | (phases.size() ? 0x10 : 0);
- MemberStats.Phases.PersonalGUID = ObjectGuid::Empty;
- for (uint32 phaseId : phases)
- {
- WorldPackets::Party::PartyMemberPhase phase;
- phase.Id = phaseId;
- phase.Flags = 1;
- MemberStats.Phases.List.push_back(phase);
- }
+ PhasingHandler::FillPartyMemberPhase(&MemberStats.Phases, player->GetPhaseShift());
// Pet
if (player->GetPet())
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 9de54534f0e..7346b14d312 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -31,7 +31,6 @@
#include "QueryCallbackProcessor.h"
#include "SharedDefines.h"
#include <array>
-#include <set>
#include <unordered_map>
#include <unordered_set>
@@ -908,7 +907,6 @@ class TC_GAME_API WorldSession
void SendNotification(uint32 stringId, ...);
void SendPetNameInvalid(uint32 error, std::string const& name, DeclinedName *declinedName);
void SendPartyResult(PartyOperation operation, std::string const& member, PartyResult res, uint32 val = 0);
- void SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps, std::set<uint32> const& worldMapAreaSwaps);
void SendQueryTimeResponse();
void SendAuthResponse(uint32 code, bool queued, uint32 queuePos = 0);
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index d4367398ba6..8347202166d 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -34,6 +34,7 @@
#include "Opcodes.h"
#include "OutdoorPvPMgr.h"
#include "Pet.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "ReputationMgr.h"
#include "ScriptMgr.h"
@@ -1671,27 +1672,17 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app
Unit* target = aurApp->GetTarget();
- std::set<uint32> const& oldPhases = target->GetPhases();
- target->SetInPhase(GetMiscValueB(), false, apply);
-
- // call functions which may have additional effects after chainging state of unit
- // phase auras normally not expected at BG but anyway better check
if (apply)
{
+ PhasingHandler::AddPhase(target, uint32(GetMiscValueB()), true);
+
+ // call functions which may have additional effects after chainging state of unit
+ // phase auras normally not expected at BG but anyway better check
// drop flag at invisibiliy in bg
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
}
-
- if (Player* player = target->ToPlayer())
- {
- if (player->IsInWorld())
- player->GetMap()->SendUpdateTransportVisibility(player, oldPhases);
- player->SendUpdatePhasing();
- }
-
- // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases)
- if (target->IsVisible())
- target->UpdateObjectVisibility();
+ else
+ PhasingHandler::RemovePhase(target, uint32(GetMiscValueB()), true);
}
void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -1701,29 +1692,17 @@ void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, boo
Unit* target = aurApp->GetTarget();
- std::set<uint32> const& oldPhases = target->GetPhases();
- std::set<uint32> phases = sDB2Manager.GetPhasesForGroup(GetMiscValueB());
- for (auto phase : phases)
- target->SetInPhase(phase, false, apply);
-
- // call functions which may have additional effects after chainging state of unit
- // phase auras normally not expected at BG but anyway better check
if (apply)
{
+ PhasingHandler::AddPhaseGroup(target, uint32(GetMiscValueB()), true);
+
+ // call functions which may have additional effects after chainging state of unit
+ // phase auras normally not expected at BG but anyway better check
// drop flag at invisibiliy in bg
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
}
-
- if (Player* player = target->ToPlayer())
- {
- if (player->IsInWorld())
- player->GetMap()->SendUpdateTransportVisibility(player, oldPhases);
- player->SendUpdatePhasing();
- }
-
- // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases)
- if (target->IsVisible())
- target->UpdateObjectVisibility();
+ else
+ PhasingHandler::RemovePhaseGroup(target, uint32(GetMiscValueB()), true);
}
/**********************/
@@ -5964,7 +5943,7 @@ void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) con
DamageInfo dotDamageInfo(damageInfo, DOT, BASE_ATTACK, hitMask);
caster->ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_NONE, hitMask, nullptr, &dotDamageInfo, nullptr);
-
+
caster->SendSpellNonMeleeDamageLog(&damageInfo);
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 912de1a315d..0763be83110 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1302,7 +1302,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
float angle = float(rand_norm()) * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dist, angle);
- float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhases(), x, y, z, true, 50.0f);
+ float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhaseShift(), x, y, z, true, 50.0f);
float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
LiquidData liquidData;
if (m_caster->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData))
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index ceafaaf797f..a03b124f4b4 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -51,6 +51,7 @@
#include "OutdoorPvPMgr.h"
#include "PathGenerator.h"
#include "Pet.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "ReputationMgr.h"
#include "ScriptMgr.h"
@@ -3086,7 +3087,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex)
if (!go)
return;
- go->CopyPhaseFrom(m_caster);
+ PhasingHandler::InheritPhaseShift(go, m_caster);
int32 duration = m_spellInfo->CalcDuration(m_caster);
@@ -3105,7 +3106,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex)
if (GameObject* linkedTrap = go->GetLinkedTrap())
{
- linkedTrap->CopyPhaseFrom(m_caster);
+ PhasingHandler::InheritPhaseShift(linkedTrap , m_caster);
linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
linkedTrap->SetSpellId(m_spellInfo->Id);
@@ -3641,7 +3642,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex)
if (!go)
return;
- go->CopyPhaseFrom(m_caster);
+ PhasingHandler::InheritPhaseShift(go, m_caster);
go->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction());
go->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1);
@@ -3971,7 +3972,7 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex)
if (!go)
return;
- go->CopyPhaseFrom(m_caster);
+ PhasingHandler::InheritPhaseShift(go, m_caster);
//go->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
int32 duration = m_spellInfo->CalcDuration(m_caster);
@@ -4654,7 +4655,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex)
if (!go)
return;
- go->CopyPhaseFrom(m_caster);
+ PhasingHandler::InheritPhaseShift(go, m_caster);
int32 duration = m_spellInfo->CalcDuration(m_caster);
@@ -4717,7 +4718,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex)
if (GameObject* linkedTrap = go->GetLinkedTrap())
{
- linkedTrap->CopyPhaseFrom(m_caster);
+ PhasingHandler::InheritPhaseShift(linkedTrap, m_caster);
linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
//linkedTrap->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
@@ -5713,7 +5714,7 @@ void Spell::EffectUpdatePlayerPhase(SpellEffIndex /*effIndex*/)
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
- unitTarget->UpdateAreaAndZonePhase();
+ PhasingHandler::OnConditionChange(unitTarget);
}
void Spell::EffectUpdateZoneAurasAndPhases(SpellEffIndex /*effIndex*/)
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 93d4cdebadd..65f5f9bd59c 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1972,17 +1972,7 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading World States..."); // must be loaded before battleground, outdoor PvP and conditions
LoadWorldStates();
- TC_LOG_INFO("server.loading", "Loading Terrain Phase definitions...");
- sObjectMgr->LoadTerrainPhaseInfo();
-
- TC_LOG_INFO("server.loading", "Loading Terrain Swap Default definitions...");
- sObjectMgr->LoadTerrainSwapDefaults();
-
- TC_LOG_INFO("server.loading", "Loading Terrain World Map definitions...");
- sObjectMgr->LoadTerrainWorldMaps();
-
- TC_LOG_INFO("server.loading", "Loading Phase Area definitions...");
- sObjectMgr->LoadAreaPhases();
+ sObjectMgr->LoadPhases();
TC_LOG_INFO("server.loading", "Loading Conditions...");
sConditionMgr->LoadConditions();
diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp
index f2294044af3..be216e79d94 100644
--- a/src/server/scripts/Commands/cs_debug.cpp
+++ b/src/server/scripts/Commands/cs_debug.cpp
@@ -38,6 +38,7 @@ EndScriptData */
#include "MapManager.h"
#include "MovementPackets.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "RBAC.h"
#include "SpellPackets.h"
#include "Transport.h"
@@ -945,7 +946,7 @@ public:
if (!v)
return false;
- v->CopyPhaseFrom(handler->GetSession()->GetPlayer());
+ PhasingHandler::InheritPhaseShift(v, handler->GetSession()->GetPlayer());
map->AddToMap(v);
@@ -974,22 +975,20 @@ public:
if (!t)
return false;
- std::set<uint32> terrainswap;
- std::set<uint32> phaseId;
- std::set<uint32> worldMapSwap;
+ PhaseShift phaseShift;
if (uint32 ut = (uint32)atoi(t))
- terrainswap.insert(ut);
+ phaseShift.AddVisibleMapId(ut, nullptr);
if (p)
if (uint32 up = (uint32)atoi(p))
- phaseId.insert(up);
+ phaseShift.AddPhase(up, PhaseFlags::None, nullptr);
if (m)
if (uint32 um = (uint32)atoi(m))
- worldMapSwap.insert(um);
+ phaseShift.AddUiWorldMapAreaIdSwap(um);
- handler->GetSession()->SendSetPhaseShift(phaseId, terrainswap, worldMapSwap);
+ PhasingHandler::SendToPlayer(handler->GetSession()->GetPlayer(), phaseShift);
return true;
}
@@ -1472,17 +1471,7 @@ public:
else if (target->GetDBPhase() < 0)
handler->PSendSysMessage("Target creature's PhaseGroup in DB: %d", abs(target->GetDBPhase()));
- std::stringstream phases;
-
- for (uint32 phase : target->GetPhases())
- {
- phases << phase << " ";
- }
-
- if (!phases.str().empty())
- handler->PSendSysMessage("Target's current phases: %s", phases.str().c_str());
- else
- handler->SendSysMessage("Target is not phased");
+ PhasingHandler::PrintToChat(handler, target->GetPhaseShift());
return true;
}
diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp
index 3f57f2c0fbc..e2a1f8172a4 100644
--- a/src/server/scripts/Commands/cs_gobject.cpp
+++ b/src/server/scripts/Commands/cs_gobject.cpp
@@ -34,6 +34,7 @@ EndScriptData */
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "PoolMgr.h"
#include "RBAC.h"
@@ -146,7 +147,7 @@ public:
if (!object)
return false;
- object->CopyPhaseFrom(player);
+ PhasingHandler::InheritPhaseShift(object, player);
if (spawntimeSecs)
{
diff --git a/src/server/scripts/Commands/cs_group.cpp b/src/server/scripts/Commands/cs_group.cpp
index a914f2e99fc..bae4a73d959 100644
--- a/src/server/scripts/Commands/cs_group.cpp
+++ b/src/server/scripts/Commands/cs_group.cpp
@@ -26,6 +26,7 @@
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "RBAC.h"
#include "WorldSession.h"
@@ -352,7 +353,7 @@ public:
{
// ... than, it prints information like "is online", where he is, etc...
onlineState = "online";
- phases = StringJoin(p->GetPhases(), ", ");
+ phases = PhasingHandler::FormatPhases(p->GetPhaseShift());
AreaTableEntry const* area = sAreaTableStore.LookupEntry(p->GetAreaId());
if (area)
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 0993794d204..c75b528521c 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -39,6 +39,7 @@
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Pet.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "Realm.h"
#include "ScriptMgr.h"
@@ -258,8 +259,8 @@ public:
sDB2Manager.Map2ZoneCoordinates(zoneId, zoneX, zoneY);
Map const* map = object->GetMap();
- float groundZ = map->GetHeight(object->GetPhases(), object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
- float floorZ = map->GetHeight(object->GetPhases(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
+ float groundZ = map->GetHeight(object->GetPhaseShift(), object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
+ float floorZ = map->GetHeight(object->GetPhaseShift(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
GridCoord gridCoord = Trinity::ComputeGridCoord(object->GetPositionX(), object->GetPositionY());
@@ -286,7 +287,6 @@ public:
mapId, (mapEntry ? mapEntry->MapName->Str[handler->GetSessionDbcLocale()] : unknown),
zoneId, (zoneEntry ? zoneEntry->AreaName->Str[handler->GetSessionDbcLocale()] : unknown),
areaId, (areaEntry ? areaEntry->AreaName->Str[handler->GetSessionDbcLocale()] : unknown),
- StringJoin(object->GetPhases(), ", ").c_str(),
object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation());
if (Transport* transport = object->GetTransport())
handler->PSendSysMessage(LANG_TRANSPORT_POSITION,
@@ -302,20 +302,7 @@ public:
if (status)
handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, liquidStatus.type_flags, status);
- if (!object->GetTerrainSwaps().empty())
- {
- std::stringstream ss;
- for (uint32 swap : object->GetTerrainSwaps())
- ss << swap << " ";
- handler->PSendSysMessage("Target's active terrain swaps: %s", ss.str().c_str());
- }
- if (!object->GetWorldMapAreaSwaps().empty())
- {
- std::stringstream ss;
- for (uint32 swap : object->GetWorldMapAreaSwaps())
- ss << swap << " ";
- handler->PSendSysMessage("Target's active world map area swaps: %s", ss.str().c_str());
- }
+ PhasingHandler::PrintToChat(handler, object->GetPhaseShift());
return true;
}
@@ -479,7 +466,8 @@ public:
target->GetContactPoint(_player, x, y, z);
_player->TeleportTo(target->GetMapId(), x, y, z, _player->GetAngle(target), TELE_TO_GM_MODE);
- _player->CopyPhaseFrom(target, true);
+ PhasingHandler::InheritPhaseShift(_player, target);
+ _player->UpdateObjectVisibility();
}
else
{
@@ -603,7 +591,8 @@ public:
float x, y, z;
handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, target->GetObjectSize());
target->TeleportTo(handler->GetSession()->GetPlayer()->GetMapId(), x, y, z, target->GetOrientation());
- target->CopyPhaseFrom(handler->GetSession()->GetPlayer(), true);
+ PhasingHandler::InheritPhaseShift(target, handler->GetSession()->GetPlayer());
+ target->UpdateObjectVisibility();
}
else
{
@@ -1692,7 +1681,6 @@ public:
// Position data print
uint32 mapId;
uint32 areaId;
- std::set<uint32> phases;
std::string areaName = handler->GetTrinityString(LANG_UNKNOWN);
std::string zoneName = handler->GetTrinityString(LANG_UNKNOWN);
@@ -1724,7 +1712,6 @@ public:
areaId = target->GetAreaId();
alive = target->IsAlive() ? handler->GetTrinityString(LANG_YES) : handler->GetTrinityString(LANG_NO);
gender = target->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER);
- phases = target->GetPhases();
}
// get additional information from DB
else
@@ -1909,9 +1896,9 @@ public:
// Output XII. LANG_PINFO_CHR_ALIVE
handler->PSendSysMessage(LANG_PINFO_CHR_ALIVE, alive.c_str());
- // Output XIII. LANG_PINFO_CHR_PHASES
- if (target && !phases.empty())
- handler->PSendSysMessage(LANG_PINFO_CHR_PHASES, StringJoin(phases, ", ").c_str());
+ // Output XIII. phases
+ if (target)
+ PhasingHandler::PrintToChat(handler, target->GetPhaseShift());
// Output XIV. LANG_PINFO_CHR_MONEY
uint32 gold = money / GOLD;
diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp
index d7be9d12c18..a17824a0127 100644
--- a/src/server/scripts/Commands/cs_modify.cpp
+++ b/src/server/scripts/Commands/cs_modify.cpp
@@ -28,6 +28,7 @@ EndScriptData */
#include "Log.h"
#include "ObjectMgr.h"
#include "Pet.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "RBAC.h"
#include "ReputationMgr.h"
@@ -831,9 +832,18 @@ public:
if (!*args)
return false;
- uint32 phaseId = uint32(atoul(args));
+ char* phaseText = strtok((char*)args, " ");
+ if (!phaseText)
+ return false;
+
+ uint32 phaseId = uint32(strtoul(phaseText, nullptr, 10));
+ uint32 visibleMapId = 0;
+
+ char* visibleMapIdText = strtok(nullptr, " ");
+ if (visibleMapIdText)
+ visibleMapId = uint32(strtoul(visibleMapIdText, nullptr, 10));
- if (!sPhaseStore.LookupEntry(phaseId))
+ if (phaseId && !sPhaseStore.LookupEntry(phaseId))
{
handler->SendSysMessage(LANG_PHASE_NOTFOUND);
handler->SetSentErrorMessage(true);
@@ -841,13 +851,30 @@ public:
}
Unit* target = handler->getSelectedUnit();
- if (!target)
- target = handler->GetSession()->GetPlayer();
- target->SetInPhase(phaseId, true, !target->IsInPhase(phaseId));
+ if (visibleMapId)
+ {
+ MapEntry const* visibleMap = sMapStore.LookupEntry(visibleMapId);
+ if (!visibleMap || visibleMap->ParentMapID != int32(target->GetMapId()))
+ {
+ handler->SendSysMessage(LANG_PHASE_NOTFOUND);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->SendUpdatePhasing();
+ if (!target->GetPhaseShift().HasVisibleMapId(visibleMapId))
+ PhasingHandler::AddVisibleMapId(target, visibleMapId);
+ else
+ PhasingHandler::RemoveVisibleMapId(target, visibleMapId);
+ }
+
+ if (phaseId)
+ {
+ if (!target->GetPhaseShift().HasPhase(phaseId))
+ PhasingHandler::AddPhase(target, phaseId, true);
+ else
+ PhasingHandler::RemovePhase(target, phaseId, true);
+ }
return true;
}
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 2ecdd51b230..7b9d16502bb 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -33,6 +33,7 @@ EndScriptData */
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Pet.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "RBAC.h"
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
@@ -310,7 +311,7 @@ public:
if (!creature)
return false;
- creature->CopyPhaseFrom(chr);
+ PhasingHandler::InheritPhaseShift(creature, chr);
creature->SaveToDB(map->GetId(), UI64LIT(1) << map->GetSpawnMode());
ObjectGuid::LowType db_guid = creature->GetSpawnId();
@@ -762,17 +763,7 @@ public:
if (CreatureData const* data = sObjectMgr->GetCreatureData(target->GetSpawnId()))
{
handler->PSendSysMessage(LANG_NPCINFO_PHASES, data->phaseId, data->phaseGroup);
- if (data->phaseGroup)
- {
- std::set<uint32> _phases = target->GetPhases();
-
- if (!_phases.empty())
- {
- handler->PSendSysMessage(LANG_NPCINFO_PHASE_IDS);
- for (uint32 phaseId : _phases)
- handler->PSendSysMessage("%u", phaseId);
- }
- }
+ PhasingHandler::PrintToChat(handler, target->GetPhaseShift());
}
handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor());
@@ -1122,12 +1113,8 @@ public:
return false;
}
- creature->ClearPhases();
-
- for (uint32 id : sDB2Manager.GetPhasesForGroup(phaseGroupId))
- creature->SetInPhase(id, false, true); // don't send update here for multiple phases, only send it once after adding all phases
-
- creature->UpdateObjectVisibility();
+ PhasingHandler::ResetPhaseShift(creature);
+ PhasingHandler::AddPhaseGroup(creature, phaseGroupId, true);
creature->SetDBPhase(-phaseGroupId);
creature->SaveToDB();
@@ -1158,8 +1145,8 @@ public:
return false;
}
- creature->ClearPhases();
- creature->SetInPhase(phaseID, true, true);
+ PhasingHandler::ResetPhaseShift(creature);
+ PhasingHandler::AddPhase(creature, phaseID, true);
creature->SetDBPhase(phaseID);
creature->SaveToDB();
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index 438a662f2aa..df24f26bd5d 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -1127,14 +1127,6 @@ public:
return true;
}
- static bool HandleReloadPhaseDefinitionsCommand(ChatHandler* handler, const char* /*args*/)
- {
- TC_LOG_INFO("misc", "Reloading terrain_phase_info table...");
- sObjectMgr->LoadTerrainPhaseInfo();
- handler->SendGlobalGMSysMessage("Terrain phase infos reloaded.");
- return true;
- }
-
static bool HandleReloadAreaTriggerTemplateCommand(ChatHandler* handler, const char* /*args*/)
{
TC_LOG_INFO("misc", "Reloading areatrigger_template table...");
diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp
index 2fa3a081435..47f466c7c61 100644
--- a/src/server/scripts/Commands/cs_wp.cpp
+++ b/src/server/scripts/Commands/cs_wp.cpp
@@ -30,6 +30,7 @@ EndScriptData */
#include "Map.h"
#include "MotionMaster.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "RBAC.h"
#include "WaypointManager.h"
@@ -672,7 +673,7 @@ public:
return false;
}
- wpCreature->CopyPhaseFrom(chr);
+ PhasingHandler::InheritPhaseShift(wpCreature, chr);
wpCreature->SaveToDB(map->GetId(), UI64LIT(1) << map->GetSpawnMode());
ObjectGuid::LowType dbGuid = wpCreature->GetSpawnId();
@@ -890,7 +891,7 @@ public:
return false;
}
- wpCreature->CopyPhaseFrom(chr);
+ PhasingHandler::InheritPhaseShift(wpCreature, chr);
wpCreature->SaveToDB(map->GetId(), UI64LIT(1) << map->GetSpawnMode());
ObjectGuid::LowType dbGuid = wpCreature->GetSpawnId();
@@ -959,7 +960,7 @@ public:
return false;
}
- creature->CopyPhaseFrom(chr);
+ PhasingHandler::InheritPhaseShift(creature, chr);
creature->SaveToDB(map->GetId(), UI64LIT(1) << map->GetSpawnMode());
ObjectGuid::LowType dbGuid = creature->GetSpawnId();
@@ -1016,7 +1017,7 @@ public:
return false;
}
- creature->CopyPhaseFrom(chr);
+ PhasingHandler::InheritPhaseShift(creature, chr);
creature->SaveToDB(map->GetId(), UI64LIT(1) << map->GetSpawnMode());
ObjectGuid::LowType dbGuid = creature->GetSpawnId();
diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp
index 9f19dd92598..f16ad9f3f26 100644
--- a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp
+++ b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp
@@ -543,7 +543,7 @@ public:
float x = caster->GetPositionX() + dist * std::cos(angle);
float y = caster->GetPositionY() + dist * std::sin(angle);
- float z = caster->GetMap()->GetHeight(caster->GetPhases(), x, y, caster->GetPositionZ());
+ float z = caster->GetMap()->GetHeight(caster->GetPhaseShift(), x, y, caster->GetPositionZ());
float o = dest._position.GetOrientation();
dest.Relocate({ x, y, z, o });
diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp
index 0a324f1164b..52fd5df153c 100644
--- a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp
+++ b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp
@@ -484,7 +484,7 @@ public:
{
Unit* caster = GetCaster();
Position pos = caster->GetPosition();
- pos.m_positionZ = caster->GetMap()->GetHeight(caster->GetPhases(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, 100.0f);
+ pos.m_positionZ = caster->GetMap()->GetHeight(caster->GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, 100.0f);
dest.Relocate(pos);
}
diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp
index 79aae3f5863..6488bc1f5d5 100644
--- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp
+++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp
@@ -24,6 +24,7 @@
#include "InstanceScript.h"
#include "Map.h"
#include "ObjectAccessor.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
@@ -147,7 +148,7 @@ public:
// clone
player->CastSpell(summon, SPELL_CLONE_PLAYER, true);
// phase the summon
- summon->SetInPhase(spellInfo->GetEffect(EFFECT_0)->MiscValueB, true, true);
+ PhasingHandler::AddPhase(summon, spellInfo->GetEffect(EFFECT_0)->MiscValueB, true);
}
}
++insanityHandled;
@@ -173,9 +174,9 @@ public:
instance->DoStopCriteriaTimer(CRITERIA_TIMED_TYPE_EVENT, ACHIEV_QUICK_DEMISE_START_EVENT);
// Visible for all players in insanity
- me->SetInPhase(169, true, true);
for (uint32 i = 173; i <= 177; ++i)
- me->SetInPhase(i, true, true);
+ PhasingHandler::AddPhase(me, i, false);
+ PhasingHandler::AddPhase(me, 169, true);
ResetPlayersPhase();
@@ -213,7 +214,7 @@ public:
return;
else
{
- nextPhase = *visage->GetPhases().begin();
+ nextPhase = visage->GetPhaseShift().GetPhases().begin()->Id;
break;
}
}
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
index d889dd42cdd..1880bfc61e6 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp
@@ -22,6 +22,7 @@
#include "InstanceScript.h"
#include "Map.h"
#include "ObjectAccessor.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "ruby_sanctum.h"
#include "ScriptedCreature.h"
@@ -408,7 +409,7 @@ class boss_twilight_halion : public CreatureScript
DoCast(me, SPELL_DUSK_SHROUD, true);
me->SetHealth(halion->GetHealth());
- me->SetInPhase(174, false, true);
+ PhasingHandler::AddPhase(me, 174, false);
me->SetReactState(REACT_DEFENSIVE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
events.ScheduleEvent(EVENT_TAIL_LASH, Seconds(12));
@@ -1211,16 +1212,16 @@ class npc_combustion_consumption : public CreatureScript
case NPC_COMBUSTION:
_explosionSpell = SPELL_FIERY_COMBUSTION_EXPLOSION;
_damageSpell = SPELL_COMBUSTION_DAMAGE_AURA;
- creature->SetInPhase(DEFAULT_PHASE, false, true);
+ PhasingHandler::AddPhase(creature, DEFAULT_PHASE, false);
if (IsHeroic())
- creature->SetInPhase(174, false, true);
+ PhasingHandler::AddPhase(creature, 174, false);
break;
case NPC_CONSUMPTION:
_explosionSpell = SPELL_SOUL_CONSUMPTION_EXPLOSION;
_damageSpell = SPELL_CONSUMPTION_DAMAGE_AURA;
- creature->SetInPhase(174, false, true);
+ PhasingHandler::AddPhase(creature, 174, false);
if (IsHeroic())
- creature->SetInPhase(DEFAULT_PHASE, false, true);
+ PhasingHandler::AddPhase(creature, DEFAULT_PHASE, false);
break;
default: // Should never happen
_explosionSpell = 0;
@@ -1357,12 +1358,12 @@ class go_twilight_portal : public GameObjectScript
switch (gameobject->GetEntry())
{
case GO_HALION_PORTAL_EXIT:
- gameobject->SetInPhase(174, false, true);
+ PhasingHandler::AddPhase(gameobject, 174, false);
_spellId = gameobject->GetGOInfo()->goober.spell;
break;
case GO_HALION_PORTAL_1:
case GO_HALION_PORTAL_2:
- gameobject->SetInPhase(DEFAULT_PHASE, false, true);
+ PhasingHandler::AddPhase(gameobject, DEFAULT_PHASE, false);
/// Because WDB template has non-existent spell ID, not seen in sniffs either, meh
_spellId = SPELL_TWILIGHT_REALM;
break;
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
index f829093c5a5..ecd030b9304 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp
@@ -23,6 +23,7 @@
#include "halls_of_reflection.h"
#include "InstanceScript.h"
#include "Map.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "TemporarySummon.h"
#include "Transport.h"
@@ -143,7 +144,10 @@ class instance_halls_of_reflection : public InstanceMapScript
break;
case NPC_FROSTSWORN_GENERAL:
FrostswornGeneralGUID = creature->GetGUID();
- creature->SetInPhase(170, true, GetBossState(DATA_MARWYN) != DONE);
+ if (GetBossState(DATA_MARWYN) != DONE)
+ PhasingHandler::AddPhase(creature, 170, true);
+ else
+ PhasingHandler::RemovePhase(creature, 170, true);
break;
case NPC_JAINA_ESCAPE:
case NPC_SYLVANAS_ESCAPE:
@@ -325,7 +329,7 @@ class instance_halls_of_reflection : public InstanceMapScript
HandleGameObject(ImpenetrableDoorGUID, true);
DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 0);
if (Creature* general = instance->GetCreature(FrostswornGeneralGUID))
- general->SetInPhase(170, true, false);
+ PhasingHandler::RemovePhase(general, 170, true);
SpawnGunship();
SpawnEscapeEvent();
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
index 9fd0eb7beb6..a9c638c010d 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
@@ -816,7 +816,7 @@ class boss_prince_valanar_icc : public CreatureScript
{
float x, y, z;
summon->GetPosition(x, y, z);
- float ground_Z = summon->GetMap()->GetHeight(summon->GetPhases(), x, y, z, true, 500.0f);
+ float ground_Z = summon->GetMap()->GetHeight(summon->GetPhaseShift(), x, y, z, true, 500.0f);
summon->GetMotionMaster()->MovePoint(POINT_KINETIC_BOMB_IMPACT, x, y, ground_Z);
summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
break;
@@ -1058,7 +1058,7 @@ class npc_kinetic_bomb : public CreatureScript
me->SetReactState(REACT_PASSIVE);
me->GetPosition(_x, _y, _groundZ);
me->DespawnOrUnsummon(60000);
- _groundZ = me->GetMap()->GetHeight(me->GetPhases(), _x, _y, _groundZ, true, 500.0f);
+ _groundZ = me->GetMap()->GetHeight(me->GetPhaseShift(), _x, _y, _groundZ, true, 500.0f);
}
void DoAction(int32 action) override
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp
index 52d6ce43b23..32f26de6698 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp
@@ -21,6 +21,7 @@
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "ObjectAccessor.h"
+#include "PhasingHandler.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
#include "SpellInfo.h"
@@ -637,7 +638,7 @@ class npc_the_lich_king_controller : public CreatureScript
void JustSummoned(Creature* summon) override
{
// must not be in dream phase
- summon->SetInPhase(173, true, false);
+ PhasingHandler::RemovePhase(summon, 173, true);
if (summon->GetEntry() != NPC_SUPPRESSER)
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
summon->AI()->AttackStart(target);
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
index 16807804090..7b83c2bc43d 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp
@@ -24,6 +24,7 @@
#include "Map.h"
#include "MotionMaster.h"
#include "oculus.h"
+#include "PhasingHandler.h"
#include "TemporarySummon.h"
#include "WorldStatePackets.h"
@@ -62,15 +63,24 @@ class instance_oculus : public InstanceMapScript
break;
case NPC_VAROS:
VarosGUID = creature->GetGUID();
- creature->SetInPhase(170, true, GetBossState(DATA_DRAKOS) != DONE);
+ if (GetBossState(DATA_DRAKOS) != DONE)
+ PhasingHandler::AddPhase(creature, 170, true);
+ else
+ PhasingHandler::RemovePhase(creature, 170, true);
break;
case NPC_UROM:
UromGUID = creature->GetGUID();
- creature->SetInPhase(170, true, GetBossState(DATA_VAROS) != DONE);
+ if (GetBossState(DATA_VAROS) != DONE)
+ PhasingHandler::AddPhase(creature, 170, true);
+ else
+ PhasingHandler::RemovePhase(creature, 170, true);
break;
case NPC_EREGOS:
EregosGUID = creature->GetGUID();
- creature->SetInPhase(170, true, GetBossState(DATA_UROM) != DONE);
+ if (GetBossState(DATA_UROM) != DONE)
+ PhasingHandler::AddPhase(creature, 170, true);
+ else
+ PhasingHandler::RemovePhase(creature, 170, true);
break;
case NPC_CENTRIFUGE_CONSTRUCT:
if (creature->IsAlive())
@@ -104,8 +114,7 @@ class instance_oculus : public InstanceMapScript
if (GetBossState(DATA_UROM) == DONE)
GreaterWhelpList.push_back(creature->GetGUID());
else
- creature->SetInPhase(170, true, true);
-
+ PhasingHandler::AddPhase(creature, 170, true);
break;
default:
break;
@@ -194,7 +203,7 @@ class instance_oculus : public InstanceMapScript
DoUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_AMOUNT, CentrifugueConstructCounter);
FreeDragons();
if (Creature* varos = instance->GetCreature(VarosGUID))
- varos->SetInPhase(170, true, false);
+ PhasingHandler::RemovePhase(varos, 170, true);
events.ScheduleEvent(EVENT_VAROS_INTRO, 15000);
}
break;
@@ -203,7 +212,7 @@ class instance_oculus : public InstanceMapScript
{
DoUpdateWorldState(WORLD_STATE_CENTRIFUGE_CONSTRUCT_SHOW, 0);
if (Creature* urom = instance->GetCreature(UromGUID))
- urom->SetInPhase(170, true, false);
+ PhasingHandler::RemovePhase(urom, 170, true);
}
break;
case DATA_UROM:
@@ -211,7 +220,7 @@ class instance_oculus : public InstanceMapScript
{
if (Creature* eregos = instance->GetCreature(EregosGUID))
{
- eregos->SetInPhase(170, true, false);
+ PhasingHandler::RemovePhase(eregos, 170, true);
GreaterWhelps();
events.ScheduleEvent(EVENT_EREGOS_INTRO, 5000);
}
@@ -313,7 +322,7 @@ class instance_oculus : public InstanceMapScript
{
for (ObjectGuid guid : GreaterWhelpList)
if (Creature* gwhelp = instance->GetCreature(guid))
- gwhelp->SetInPhase(170, true, false);
+ PhasingHandler::RemovePhase(gwhelp, 170, true);
}
protected:
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
index 04f9f8e46bb..93f1f515409 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
@@ -777,7 +777,7 @@ class boss_flame_leviathan_safety_container : public CreatureScript
{
float x, y, z;
me->GetPosition(x, y, z);
- z = me->GetMap()->GetHeight(me->GetPhases(), x, y, z);
+ z = me->GetMap()->GetHeight(me->GetPhaseShift(), x, y, z);
me->GetMotionMaster()->MovePoint(0, x, y, z);
me->SetPosition(x, y, z, 0);
}
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
index 5a726140a70..8ecccb016ea 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp
@@ -872,7 +872,7 @@ class boss_sara : public CreatureScript
float angle = frand(0.0f, 2.0f * float(M_PI));
pos.m_positionX = YoggSaronSpawnPos.GetPositionX() + radius * cosf(angle);
pos.m_positionY = YoggSaronSpawnPos.GetPositionY() + radius * sinf(angle);
- pos.m_positionZ = me->GetMap()->GetHeight(me->GetPhases(), pos.GetPositionX(), pos.GetPositionY(), YoggSaronSpawnPos.GetPositionZ() + 5.0f);
+ pos.m_positionZ = me->GetMap()->GetHeight(me->GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), YoggSaronSpawnPos.GetPositionZ() + 5.0f);
me->SummonCreature(NPC_DEATH_RAY, pos, TEMPSUMMON_TIMED_DESPAWN, 20000);
}
break;
diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp
index 3cd437f4111..7ee188693fb 100644
--- a/src/server/scripts/Northrend/zone_borean_tundra.cpp
+++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp
@@ -38,6 +38,7 @@ EndContentData */
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "ScriptedEscortAI.h"
#include "ScriptedFollowerAI.h"
@@ -1678,7 +1679,7 @@ public:
me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);
break;
case 20:
- me->SetInPhase(170, true, false);
+ PhasingHandler::RemovePhase(me, 170, true);
Talk(SAY_5);
me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);
player->GroupEventHappens(QUEST_ESCAPING_THE_MIST, me);
diff --git a/src/server/scripts/Northrend/zone_sholazar_basin.cpp b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
index 2b0e071d239..f3eb8735bcf 100644
--- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp
+++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
@@ -783,7 +783,7 @@ public:
bird->KillSelf();
crunchy->GetMotionMaster()->MovePoint(0, bird->GetPositionX(), bird->GetPositionY(),
- bird->GetMap()->GetWaterOrGroundLevel(bird->GetPhases(), bird->GetPositionX(), bird->GetPositionY(), bird->GetPositionZ()));
+ bird->GetMap()->GetWaterOrGroundLevel(bird->GetPhaseShift(), bird->GetPositionX(), bird->GetPositionY(), bird->GetPositionZ()));
/// @todo Make crunchy perform emote eat when he reaches the bird
break;
diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp
index d259e8585c6..5c5bf2d967b 100644
--- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp
+++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp
@@ -22,6 +22,7 @@
#include "Map.h"
#include "ObjectMgr.h"
#include "OutdoorPvPSI.h"
+#include "PhasingHandler.h"
#include "Player.h"
#include "ReputationMgr.h"
#include "World.h"
@@ -158,7 +159,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId)
Map* map = player->GetMap();
if (GameObject* go = GameObject::CreateGameObject(SI_SILITHYST_MOUND, map, *player, QuaternionData(), 255, GO_STATE_READY))
{
- go->CopyPhaseFrom(player);
+ PhasingHandler::InheritPhaseShift(go, player);
go->SetRespawnTime(0);
if (!map->AddToMap(go))