diff options
author | Shauren <shauren.trinity@gmail.com> | 2018-01-28 11:37:20 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2018-03-25 19:28:36 +0300 |
commit | 91be2332e249147ce3169c46a7da77f0f8c2211d (patch) | |
tree | eab9e0ab76ae523f7a843fe1c2300eba17f53af2 /src | |
parent | 1e62b53c66829dc9820117e17bfb44cb2652f814 (diff) |
Core/Entities: Phasing rewrite
* Optimized phase visibility checking
* Handle all phase flags
Closes #16758
Closes #21119
Diffstat (limited to 'src')
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)) |