diff --git a/sql/updates/world/4.3.4/2018_03_08_00_world.sql b/sql/updates/world/4.3.4/2018_03_08_00_world.sql new file mode 100644 index 00000000000..83f9ca2a582 --- /dev/null +++ b/sql/updates/world/4.3.4/2018_03_08_00_world.sql @@ -0,0 +1,22 @@ +ALTER TABLE `creature` + ADD `phaseUseFlags` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `spawnMask`, + ADD `terrainSwapMap` int(11) NOT NULL DEFAULT '-1' AFTER `PhaseGroup`; + +ALTER TABLE `gameobject` + ADD `phaseUseFlags` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `spawnMask`, + ADD `terrainSwapMap` int(11) NOT NULL DEFAULT '-1' AFTER `PhaseGroup`; + +DROP TABLE `terrain_phase_info`; + +ALTER TABLE `transports` ADD `phaseUseFlags` tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER `name`; + +DELETE FROM `trinity_string` WHERE `entry` IN (101,178,179,180,181,182,183,184,185); +INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES +(101,'Map: %u (%s) Zone: %u (%s) Area: %u (%s)\nX: %f Y: %f Z: %f Orientation: %f'), +(178,'grid[%u,%u]cell[%u,%u] InstanceID: %u\n ZoneX: %f ZoneY: %f\nGroundZ: %f FloorZ: %f Have height data (Map: %u VMap: %u MMap: %u)'), +(179,'PhaseShift:\n* Flags %u, PersonalGuid: %s'), +(180,'* Phases: %s'), +(181,'* VisibleMapIds: %s'), +(182,'* UiWorldMapAreaSwaps: %s'), +(183,'Cosmetic'), +(184,'Personal'); diff --git a/src/common/Collision/DynamicTree.cpp b/src/common/Collision/DynamicTree.cpp index 750e155da87..f86cccbf0a9 100644 --- a/src/common/Collision/DynamicTree.cpp +++ b/src/common/Collision/DynamicTree.cpp @@ -142,11 +142,11 @@ void DynamicMapTree::update(uint32 t_diff) struct DynamicTreeIntersectionCallback { - DynamicTreeIntersectionCallback(std::set 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, VMAP::ModelIgnoreFlags::Nothing); + _didHit = obj.intersectRay(r, distance, true, _phaseShift, VMAP::ModelIgnoreFlags::Nothing); return _didHit; } @@ -154,20 +154,20 @@ struct DynamicTreeIntersectionCallback private: bool _didHit; - std::set _phases; + PhaseShift const& _phaseShift; }; -bool DynamicMapTree::getIntersectionTime(std::set 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 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(); @@ -182,7 +182,7 @@ bool DynamicMapTree::getObjectHitPos(std::set 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) @@ -205,7 +205,7 @@ bool DynamicMapTree::getObjectHitPos(std::set const& phases, G3D::Vector return result; } -bool DynamicMapTree::isInLineOfSight(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, std::set const& phases) const +bool DynamicMapTree::isInLineOfSight(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, PhaseShift const& phaseShift) const { float maxDist = (endPos - startPos).magnitude(); @@ -213,17 +213,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 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 7dd7b149088..4ae49c00595 100644 --- a/src/common/Collision/DynamicTree.h +++ b/src/common/Collision/DynamicTree.h @@ -29,6 +29,7 @@ namespace G3D } class GameObjectModel; +class PhaseShift; struct DynTreeImpl; class TC_COMMON_API DynamicMapTree @@ -40,11 +41,11 @@ public: DynamicMapTree(); ~DynamicMapTree(); - bool isInLineOfSight(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, std::set const& phases) const; - bool getIntersectionTime(std::set const& phases, G3D::Ray const& ray, G3D::Vector3 const& endPos, float& maxDist) const; - bool getObjectHitPos(std::set 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 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 9643f029078..219026c12e5 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 const& phases, VMAP::ModelIgnoreFlags ignoreFlags) const +bool GameObjectModel::intersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, PhaseShift const& phaseShift, VMAP::ModelIgnoreFlags ignoreFlags) 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 e0de8ea7a18..a8dd8547750 100644 --- a/src/common/Collision/Models/GameObjectModel.h +++ b/src/common/Collision/Models/GameObjectModel.h @@ -26,7 +26,6 @@ #include "Define.h" #include -#include namespace VMAP { @@ -35,6 +34,7 @@ namespace VMAP } class GameObject; +class PhaseShift; struct GameObjectDisplayInfoEntry; class TC_COMMON_API GameObjectModelOwnerBase @@ -42,7 +42,7 @@ class TC_COMMON_API GameObjectModelOwnerBase public: virtual bool IsSpawned() const { return false; } virtual uint32 GetDisplayId() const { return 0; } - virtual bool IsInPhase(std::set 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 const& phases, VMAP::ModelIgnoreFlags ignoreFlags) const; + bool intersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, PhaseShift const& phaseShift, VMAP::ModelIgnoreFlags ignoreFlags) const; static GameObjectModel* Create(std::unique_ptr modelOwner, std::string const& dataPath); diff --git a/src/common/Utilities/Containers.h b/src/common/Utilities/Containers.h index db762a67d07..c6c9c58b253 100644 --- a/src/common/Utilities/Containers.h +++ b/src/common/Utilities/Containers.h @@ -132,7 +132,7 @@ namespace Trinity * Note: container cannot be empty */ template - 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 weights; weights.reserve(Size(container)); @@ -175,7 +175,7 @@ namespace Trinity * @return true if containers have a common element, false otherwise. */ template - 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) { @@ -190,6 +190,37 @@ namespace Trinity return false; } + /** + * @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 + 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) */ @@ -201,7 +232,7 @@ namespace Trinity } template class M, class... Rest> - void MultimapErasePair(M& multimap, K const& key, V const& value) + inline void MultimapErasePair(M& 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 + * + * 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 . + */ + +#ifndef EnumClassFlag_h__ +#define EnumClassFlag_h__ + +#include + +template +class EnumClassFlag +{ + static_assert(std::is_enum::value, "EnumClassFlag must be used only with enums"); + +public: + /*implicit*/ EnumClassFlag(T value) : _value(value) { } + + EnumClassFlag& operator&=(EnumClassFlag right) + { + _value = static_cast(static_cast>(_value) & static_cast>(right._value)); + return *this; + } + + friend EnumClassFlag operator&(EnumClassFlag left, EnumClassFlag right) + { + return left &= right; + } + + EnumClassFlag operator|=(EnumClassFlag right) + { + _value = static_cast(static_cast>(_value) | static_cast>(right._value)); + return *this; + } + + friend EnumClassFlag operator|(EnumClassFlag left, EnumClassFlag right) + { + return left |= right; + } + + EnumClassFlag operator~() const + { + return static_cast(~static_cast>(_value)); + } + + void RemoveFlag(EnumClassFlag flag) + { + _value = static_cast(static_cast>(_value) & ~static_cast>(flag._value)); + } + + bool HasFlag(T flag) const + { + return (static_cast>(_value) & static_cast>(flag)) != 0; + } + + operator T() const + { + return _value; + } + + std::underlying_type_t AsUnderlyingType() const + { + return static_cast>(_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 d7c0e079108..c5aebd382bd 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -29,6 +29,7 @@ #include "Language.h" #include "ObjectDefines.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "SmartAI.h" @@ -1130,7 +1131,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; @@ -1142,11 +1148,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!targets) break; - std::set const& phases = 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 f0f5f9d5c83..833cc9a3145 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -1337,7 +1337,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) return false; } - if (phaseGroup && GetPhasesForGroup(phaseGroup).empty()) + if (phaseGroup && GetPhasesForGroup(phaseGroup)) { TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid phase group id %u for creature %u, skipped", phaseGroup, e.entryOrGuid); return false; diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 0c4deab3b3f..9b563b716c0 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -1208,7 +1208,7 @@ LocaleConstant ChatHandler::GetSessionDbcLocale() const return m_session->GetSessionDbcLocale(); } -int ChatHandler::GetSessionDbLocaleIndex() const +LocaleConstant ChatHandler::GetSessionDbLocaleIndex() const { return m_session->GetSessionDbLocaleIndex(); } @@ -1304,7 +1304,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 7b6cb6ebe91..ef6c5b2c66f 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -112,7 +112,7 @@ class TC_GAME_API ChatHandler virtual std::string GetNameLink() const { return GetNameLink(m_session->GetPlayer()); } 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); @@ -178,7 +178,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 9f2a16f3a90..eab3f387f1a 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -21,6 +21,7 @@ #include "GameEventMgr.h" #include "InstanceScript.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "Pet.h" #include "ReputationMgr.h" @@ -402,7 +403,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const } case CONDITION_PHASEID: { - condMeets = object->IsInPhase(ConditionValue1); + condMeets = object->GetPhaseShift().HasPhase(ConditionValue1); break; } case CONDITION_TITLE: @@ -430,7 +431,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const } case CONDITION_TERRAIN_SWAP: { - condMeets = object->IsInTerrainSwap(ConditionValue1); + condMeets = object->GetPhaseShift().HasVisibleMapId(ConditionValue1); break; } case CONDITION_REALM_ACHIEVEMENT: @@ -1040,17 +1041,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, " @@ -1417,24 +1408,32 @@ bool ConditionMgr::addToPhases(Condition* cond) const { if (!cond->SourceEntry) { - PhaseInfo& p = sObjectMgr->GetAreaPhasesForLoading(); - 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* phases = const_cast*>(sObjectMgr->GetPhasesForArea(areaId))) { - phase.Conditions.push_back(cond); - return true; + for (PhaseAreaInfo& phase : *phases) + { + if (phase.PhaseInfo->Id == cond->SourceGroup) + { + phase.Conditions.push_back(cond); + found = true; + } + } } } + if (found) + return true; } } - else if (std::vector* phases = sObjectMgr->GetPhasesForAreaForLoading(cond->SourceEntry)) + else if (std::vector* phases = const_cast*>(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; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 21f2a4a5d68..e8a8c2f70a3 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -466,6 +466,23 @@ enum MountCapabilityFlags MOUNT_CAPABIILTY_FLAG_IGNORE_RESTRICTIONS = 0x20, }; +enum PhaseEntryFlags : uint16 +{ + PHASE_FLAG_NORMAL = 0x08, + PHASE_FLAG_COSMETIC = 0x10, + PHASE_FLAG_PERSONAL = 0x20 +}; + +// PhaseUseFlags fields in different DBCs +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 SkillRaceClassInfoFlags { SKILL_FLAG_NO_SKILLUP_MESSAGE = 0x2, diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 240dc156ed3..6a608eff843 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -558,7 +558,7 @@ void LoadDBCStores(const std::string& dataPath) for (uint32 i = 0; i < sPhaseGroupStore.GetNumRows(); ++i) if (PhaseGroupEntry const* group = sPhaseGroupStore.LookupEntry(i)) if (PhaseEntry const* phase = sPhaseStore.LookupEntry(group->PhaseId)) - sPhasesByGroup[group->GroupId].insert(phase->ID); + sPhasesByGroup[group->GroupId].push_back(phase->ID); LoadDBC(availableDbcLocales, bad_dbc_files, sPowerDisplayStore, dbcPath, "PowerDisplay.dbc"); @@ -1360,9 +1360,9 @@ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, u return NULL; } -std::set const& GetPhasesForGroup(uint32 group) +std::vector const* GetPhasesForGroup(uint32 group) { - return sPhasesByGroup[group]; + return &sPhasesByGroup[group]; } ResponseCodes ValidateName(std::wstring const& name, LocaleConstant locale) diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 05833b05528..448a64759ee 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -81,7 +81,7 @@ TC_GAME_API LFGDungeonEntry const* GetLFGDungeon(uint32 mapId, Difficulty diffic uint32 GetDefaultMapLight(uint32 mapId); -TC_GAME_API std::set const& GetPhasesForGroup(uint32 group); +TC_GAME_API std::vector const* GetPhasesForGroup(uint32 group); typedef std::unordered_multimap SkillRaceClassInfoMap; typedef std::pair SkillRaceClassInfoBounds; @@ -254,7 +254,7 @@ TC_GAME_API extern DBCStorage sUnitPowerBarStore; TC_GAME_API extern DBCStorage sVehicleStore; TC_GAME_API extern DBCStorage sVehicleSeatStore; TC_GAME_API extern DBCStorage sWMOAreaTableStore; -//TC_GAME_API extern DBCStorage sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates +TC_GAME_API extern DBCStorage sWorldMapAreaStore; TC_GAME_API extern DBCStorage sWorldMapOverlayStore; TC_GAME_API extern DBCStorage sWorldSafeLocsStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index b06220cecf2..53e6203f9c5 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1601,7 +1601,7 @@ struct PhaseEntry { uint32 ID; // 0 char* Name; // 1 - uint32 flag; // 2 + uint32 Flags; // 2 }; struct PhaseGroupEntry @@ -2734,5 +2734,5 @@ typedef std::vector TaxiPathNodesByPath; #define TaxiMaskSize 114 typedef uint8 TaxiMask[TaxiMaskSize]; -typedef std::unordered_map> PhaseGroupContainer; +typedef std::unordered_map> PhaseGroupContainer; #endif diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index e362e1d5557..42e78d066d9 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -16,6 +16,7 @@ */ #include "ObjectAccessor.h" +#include "PhasingHandler.h" #include "Unit.h" #include "SpellInfo.h" #include "Log.h" @@ -78,7 +79,7 @@ bool AreaTrigger::CreateAreaTrigger(uint32 guidlow, uint32 triggerEntry, Unit* c SetFloatValue(AREATRIGGER_FINAL_POS + 1, pos.GetPositionY()); SetFloatValue(AREATRIGGER_FINAL_POS + 2, pos.GetPositionZ()); - CopyPhaseFrom(caster); + PhasingHandler::InheritPhaseShift(this, caster); if (!GetMap()->AddToMap(this)) return false; diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index f7be38c88ea..83df48db009 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -22,6 +22,7 @@ #include "Player.h" #include "UpdateMask.h" #include "ObjectAccessor.h" +#include "PhasingHandler.h" #include "DatabaseEnv.h" #include "World.h" @@ -86,7 +87,7 @@ bool Corpse::Create(ObjectGuid::LowType guidlow, Player* owner) _cellCoord = Trinity::ComputeCellCoord(GetPositionX(), GetPositionY()); - CopyPhaseFrom(owner); + PhasingHandler::InheritPhaseShift(this, owner); return true; } @@ -116,12 +117,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->setUInt32(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 9a037781bec..1c3ed3dd08d 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -37,6 +37,7 @@ #include "LootMgr.h" #include "MoveSpline.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "PoolMgr.h" #include "QuestDef.h" @@ -888,12 +889,11 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 /*phaseMask* ASSERT(map); SetMap(map); - if (data && data->phaseid) - SetInPhase(data->phaseid, false, true); - - if (data && data->phaseGroup) - for (auto ph : 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) @@ -1157,7 +1157,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) data.unit_flags = unit_flags; data.dynamicflags = dynamicflags; - data.phaseid = GetDBPhase() > 0 ? GetDBPhase() : 0; + data.phaseId = GetDBPhase() > 0 ? GetDBPhase() : 0; data.phaseGroup = GetDBPhase() < 0 ? abs(GetDBPhase()) : 0; // update in DB @@ -1176,7 +1176,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) stmt->setUInt16(index++, uint16(mapid)); stmt->setUInt8(index++, spawnMask); stmt->setUInt32(index++, GetPhaseMask()); - stmt->setUInt32(index++, data.phaseid); + stmt->setUInt32(index++, data.phaseId); stmt->setUInt32(index++, data.phaseGroup); stmt->setUInt32(index++, displayId); stmt->setInt32(index++, int32(GetCurrentEquipmentId())); @@ -1437,7 +1437,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); } @@ -2701,7 +2701,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 = GetFloorZ(); + 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/Creature.h b/src/server/game/Entities/Creature/Creature.h index eb500405d9b..bad63dbd7c8 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -274,7 +274,8 @@ struct CreatureData CreatureData() : id(0), mapid(0), phaseMask(0), displayid(0), equipmentId(0), 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), dynamicflags(0), phaseid(0), phaseGroup(0), ScriptId(0), dbData(true) { } + spawnMask(0), npcflag(0), unit_flags(0), dynamicflags(0), phaseUseFlags(0), + phaseId(0), phaseGroup(0), terrainSwapMap(-1), ScriptId(0), dbData(true) { } uint32 id; // entry in creature_template uint16 mapid; uint32 phaseMask; @@ -294,8 +295,10 @@ struct CreatureData uint32 npcflag; uint32 unit_flags; // enum UnitFlags mask values uint32 dynamicflags; - uint32 phaseid; + 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 3da93a3553a..6ae70163840 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -27,6 +27,7 @@ #include "GroupMgr.h" #include "ObjectMgr.h" #include "OutdoorPvPMgr.h" +#include "PhasingHandler.h" #include "PoolMgr.h" #include "ScriptMgr.h" #include "SpellMgr.h" @@ -907,15 +908,8 @@ bool GameObject::LoadGameObjectFromDB(ObjectGuid::LowType spawnId, Map* map, boo if (!Create(map->GenerateLowGuid(), entry, map, phaseMask, 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 : 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) { @@ -2476,7 +2470,6 @@ public: virtual bool IsSpawned() const override { return _owner->isSpawned(); } virtual uint32 GetDisplayId() const override { return _owner->GetDisplayId(); } - virtual bool IsInPhase(std::set const& phases) const override { return _owner->IsInPhase(phases); } 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/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index c2076a13acf..5780342bab8 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -644,7 +644,8 @@ enum GOState struct GameObjectData { explicit GameObjectData() : id(0), mapid(0), phaseMask(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; uint32 phaseMask; @@ -658,8 +659,10 @@ struct GameObjectData GOState go_state; uint8 spawnMask; uint8 artKit; - uint32 phaseid; + 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 cd10148bbbe..7d1b5839f37 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -45,6 +45,7 @@ #include "TemporarySummon.h" #include "Totem.h" #include "OutdoorPvPMgr.h" +#include "PhasingHandler.h" #include "MovementPacketBuilder.h" #include "DynamicTree.h" #include "Unit.h" @@ -1446,7 +1447,7 @@ bool WorldObject::IsWithinLOS(float ox, float oy, float oz, LineOfSightChecks ch else GetHitSpherePointFor({ ox, oy, oz }, x, y, z); - return GetMap()->isInLineOfSight(x, y, z + 2.0f, ox, oy, oz + 2.0f, GetPhases(), checks, ignoreFlags); + return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z + 2.0f, ox, oy, oz + 2.0f, checks, ignoreFlags); } return true; @@ -1621,7 +1622,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 } @@ -1643,8 +1644,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) @@ -1655,7 +1656,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; } @@ -1667,7 +1668,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) @@ -1678,7 +1679,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; } @@ -1686,7 +1687,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; @@ -2100,7 +2101,7 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert } // Set the summon to the summoner's phase - summon->CopyPhaseFrom(summoner); + PhasingHandler::InheritPhaseShift(summon, summoner); summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId); @@ -2204,7 +2205,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, Position const& pos, G3D return nullptr; } - go->CopyPhaseFrom(this); + PhasingHandler::InheritPhaseShift(go, this); go->SetRespawnTime(respawnTime); if (GetTypeId() == TYPEID_PLAYER || (GetTypeId() == TYPEID_UNIT && summonType == GO_SUMMON_TIMED_OR_CORPSE_DESPAWN)) //not sure how to handle this @@ -2430,8 +2431,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; @@ -2443,8 +2444,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 @@ -2464,8 +2465,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 { @@ -2514,7 +2515,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) @@ -2557,165 +2558,6 @@ void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) UpdateObjectVisibility(); } -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::UpdateAreaPhase() -{ - bool updateNeeded = false; - PhaseInfo const& phases = sObjectMgr->GetAreaPhases(); - for (PhaseInfo::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - { - uint32 areaId = itr->first; - for (PhaseInfoStruct const& phase : itr->second) - { - if (areaId == GetAreaId()) - { - if (sConditionMgr->IsObjectMeetToConditions(this, phase.Conditions)) - { - // add new phase if condition passed, true if it wasnt added before - bool up = SetInPhase(phase.Id, false, true); - if (!updateNeeded && up) - updateNeeded = true; - } - else - { - // condition failed, remove phase, true if there was something removed - bool up = SetInPhase(phase.Id, false, false); - if (!updateNeeded && up) - updateNeeded = true; - } - } - else - { - // not in area, remove phase, true if there was something removed - bool up = SetInPhase(phase.Id, false, false); - if (!updateNeeded && up) - updateNeeded = true; - } - } - } - - // 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()); - bool up = SetInPhase(phase, false, true); - if (!updateNeeded && up) - updateNeeded = true; - } - Unit::AuraEffectList const& auraPhaseGroupList = unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP); - for (Unit::AuraEffectList::const_iterator itr = auraPhaseGroupList.begin(); itr != auraPhaseGroupList.end(); ++itr) - { - bool up = false; - uint32 phaseGroup = uint32((*itr)->GetMiscValueB()); - std::set const& phases = GetPhasesForGroup(phaseGroup); - for (uint32 phase : phases) - up = SetInPhase(phase, false, true); - if (!updateNeeded && up) - updateNeeded = true; - } - } - - // 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) - { - if (HasInPhaseList(id)) // do not run the updates if we are already in this phase - return false; - - _phases.insert(id); - } - else - { - // 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 - PhaseInfo const& phases = sObjectMgr->GetAreaPhases(); - for (PhaseInfo::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - if (itr->first == GetAreaId() || itr->first == GetZoneId()) - for (PhaseInfoStruct const& phase : itr->second) - if (id == phase.Id) - if (sConditionMgr->IsObjectMeetToConditions(this, phase.Conditions)) - return false; - - if (!HasInPhaseList(id)) // do not run the updates if we are not in this phase - return false; - - _phases.erase(id); - } - } - - 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 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 sound_id, Player* target /*= NULL*/) { WorldPacket data(SMSG_PLAY_OBJECT_SOUND, 4 + 8); @@ -2882,7 +2724,7 @@ float WorldObject::GetFloorZ() const { if (!IsInWorld()) return m_staticFloorZ; - return std::max(m_staticFloorZ, GetMap()->GetGameObjectFloor(GetPhases(), GetPositionX(), GetPositionY(), GetPositionZ())); + return std::max(m_staticFloorZ, GetMap()->GetGameObjectFloor(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ())); } template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list&, uint32, float) const; @@ -2944,63 +2786,3 @@ void WorldObject::SetMeleeAnimKitId(uint16 animKitId) data << uint16(animKitId); SendMessageToSet(&data, true); } - -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 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->rootPhaseMap != 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 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 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 const* swaps = sObjectMgr->GetPhaseTerrainSwaps(phaseId)) - for (uint32 const& swap : *swaps) - if (std::vector const* uiMapSwaps = sObjectMgr->GetTerrainWorldMaps(swap)) - if (sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap, this)) - for (uint32 worldMapAreaId : *uiMapSwaps) - _worldMapAreaSwaps.insert(worldMapAreaId); -} diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 27788e23306..70e4c68acb5 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -24,10 +24,10 @@ #include "UpdateMask.h" #include "GridReference.h" #include "ObjectDefines.h" +#include "PhaseShift.h" #include "Map.h" #include "ModelIgnoreFlags.h" -#include #include #include @@ -48,8 +48,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 @@ -485,21 +483,16 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation uint32 GetInstanceId() const { return m_InstanceId; } virtual void SetPhaseMask(uint32 newPhaseMask, bool update); - virtual bool SetInPhase(uint32 id, bool update, bool apply); - void CopyPhaseFrom(WorldObject* obj, bool update = false); - void UpdateAreaPhase(); - void ClearPhases(bool update = false); - void RebuildTerrainSwaps(); - void RebuildWorldMapAreaSwaps(); - bool HasInPhaseList(uint32 phase); + 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; } uint32 GetPhaseMask() const { return m_phaseMask; } - bool IsInPhase(uint32 phase) const { return _phases.find(phase) != _phases.end(); } - bool IsInPhase(std::set const& phases) const; - bool IsInPhase(WorldObject const* obj) const; - bool IsInTerrainSwap(uint32 terrainSwap) const { return _terrainSwaps.find(terrainSwap) != _terrainSwaps.end(); } - std::set const& GetPhases() const { return _phases; } - std::set const& GetTerrainSwaps() const { return _terrainSwaps; } - std::set const& GetWorldMapAreaSwaps() const { return _worldMapAreaSwaps; } int32 GetDBPhase() { return _dbPhase; } // if negative it is used as PhaseGroupId @@ -699,9 +692,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 uint32 m_phaseMask; // in area phase state - std::set _phases; - std::set _terrainSwaps; - std::set _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/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index f841946b71e..fbedb7b3479 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -21,6 +21,7 @@ #include "Log.h" #include "WorldPacket.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "SpellMgr.h" #include "Pet.h" #include "Formulas.h" @@ -179,7 +180,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c if (!Create(guid, map, petEntry, petId)) 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 ca8299a1696..f83453c1402 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -65,6 +65,7 @@ #include "OutdoorPvP.h" #include "OutdoorPvPMgr.h" #include "Pet.h" +#include "PhasingHandler.h" #include "QueryCallback.h" #include "QuestDef.h" #include "ReputationMgr.h" @@ -2624,10 +2625,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); @@ -7380,7 +7384,7 @@ void Player::UpdateArea(uint32 newArea) UpdatePvPState(true); UpdateAreaDependentAuras(newArea); - UpdateAreaPhase(); + PhasingHandler::OnAreaChange(this); // previously this was in UpdateZone (but after UpdateArea) so nothing will break pvpInfo.IsInNoPvPArea = false; @@ -7485,8 +7489,6 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) UpdateLocalChannels(newZone); UpdateZoneDependentAuras(newZone); - - UpdateAreaPhase(); } //If players are too far away from the duel flag... they lose the duel @@ -16040,7 +16042,7 @@ void Player::SendQuestUpdate(uint32 questId) } UpdateForQuestWorldObjects(); - SendUpdatePhasing(); + PhasingHandler::OnConditionChange(this); } QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) @@ -23250,6 +23252,8 @@ void Player::SendInitialPacketsAfterAddToMap() else ClearQuestSharingInfo(); } + + PhasingHandler::OnMapChange(this); } void Player::SendUpdateToOutOfRangeGroupMembers() @@ -27327,7 +27331,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->SetFaction(GetFaction()); @@ -27699,16 +27703,6 @@ void Player::ReadMovementInfo(WorldPacket& data, MovementInfo* mi, Movement::Ext #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 { WorldPacket data(SMSG_SUPERCEDED_SPELL, 8); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 8394cdfead2..fff5bbf8ada 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2347,6 +2347,7 @@ class TC_GAME_API Player : public Unit, public GridObject // currently visible objects at player client GuidUnorderedSet m_clientGUIDs; + GuidUnorderedSet m_visibleTransports; bool HaveAtClient(Object const* u) const; @@ -2360,8 +2361,6 @@ class TC_GAME_API Player : public Unit, public GridObject void UpdateVisibilityOf(WorldObject* target); void UpdateTriggerVisibility(); - void SendUpdatePhasing(); - template void UpdateVisibilityOf(T* target, UpdateData& data, std::set& visibleNow); diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index ba0524c2140..6df61e1cc8b 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -20,6 +20,7 @@ #include "Transport.h" #include "MapManager.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "ScriptMgr.h" #include "DBCStores.h" #include "GameObjectAI.h" @@ -326,13 +327,8 @@ Creature* Transport::CreateNPCPassenger(ObjectGuid::LowType guid, CreatureData c return NULL; } - if (data->phaseid) - creature->SetInPhase(data->phaseid, false, true); - else if (data->phaseGroup) - for (auto phase : 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)) { @@ -377,6 +373,9 @@ GameObject* Transport::CreateGOPassenger(ObjectGuid::LowType guid, GameObjectDat return NULL; } + PhasingHandler::InitDbPhaseShift(go->GetPhaseShift(), data->phaseUseFlags, data->phaseId, data->phaseGroup); + PhasingHandler::InitDbVisibleMapId(go->GetPhaseShift(), data->terrainSwapMap); + if (!map->AddToMap(go)) { delete go; @@ -441,12 +440,6 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu } } - std::set phases; - if (summoner) - phases = summoner->GetPhases(); - else - phases = GetPhases(); // If there was no summoner, try to use the transport phases - TempSummon* summon = NULL; switch (mask) { @@ -477,8 +470,7 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu return NULL; } - for (uint32 phase : phases) - summon->SetInPhase(phase, false, true); + PhasingHandler::InheritPhaseShift(summon, summoner ? static_cast(summoner) : static_cast(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 a7f84306a66..bb31bc01edd 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -46,6 +46,7 @@ #include "PassiveAI.h" #include "PetAI.h" #include "Pet.h" +#include "PhasingHandler.h" #include "Player.h" #include "PlayerAI.h" #include "QuestDef.h" @@ -3886,7 +3887,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). @@ -3903,12 +3904,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; @@ -3923,7 +3924,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 && !aura->GetUnitOwner()->IsInPhase(this)) { aura->Remove(); iter = scAuras.begin(); @@ -10015,15 +10016,6 @@ int32 Unit::GetCreatePowers(Powers power) const return 0; } -void Unit::AddToWorld() -{ - if (!IsInWorld()) - { - WorldObject::AddToWorld(); - } - RebuildTerrainSwaps(); -} - void Unit::RemoveFromWorld() { // cleanup @@ -11343,7 +11335,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) @@ -12444,14 +12436,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(); @@ -12481,19 +12471,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]) - if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i])) - summon->SetInPhase(id, true, apply); - - RemoveNotOwnSingleTargetAuras(0, true); - - return res; } void Unit::UpdateObjectVisibility(bool forced) @@ -13274,7 +13251,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 e8ab2baa4fc..ba8f25f0a72 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1309,7 +1309,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); @@ -1795,7 +1794,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); void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except = 0); void RemoveAurasWithAttribute(uint32 flags); void RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, ObjectGuid casterGUID); @@ -1977,7 +1976,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/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index c57deb6290e..39ec0d6e960 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -23,6 +23,7 @@ #include "BattlegroundMgr.h" #include "Chat.h" #include "Common.h" +#include "Containers.h" #include "CreatureAIFactory.h" #include "DatabaseEnv.h" #include "DB2Structure.h" @@ -1828,9 +1829,9 @@ void ObjectMgr::LoadCreatures() // 0 1 2 3 4 5 6 7 8 9 10 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 22 - "currentwaypoint, curhealth, curmana, MovementType, spawnMask, phaseMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.dynamicflags, creature.phaseid, " - // 23 24 - "creature.phasegroup, creature.ScriptName " + "currentwaypoint, curhealth, curmana, MovementType, spawnMask, phaseMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.dynamicflags, creature.phaseUseFlags, " + // 23 24 25 26 + "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"); @@ -1887,9 +1888,11 @@ void ObjectMgr::LoadCreatures() data.npcflag = fields[19].GetUInt32(); data.unit_flags = fields[20].GetUInt32(); data.dynamicflags = fields[21].GetUInt32(); - data.phaseid = fields[22].GetUInt32(); - data.phaseGroup = fields[23].GetUInt32(); - data.ScriptId = GetScriptId(fields[24].GetString()); + data.phaseUseFlags = fields[22].GetUInt8(); + data.phaseId = fields[23].GetUInt32(); + data.phaseGroup = fields[24].GetUInt32(); + data.terrainSwapMap = fields[25].GetInt32(); + data.ScriptId = GetScriptId(fields[26].GetString()); MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); if (!mapEntry) @@ -1971,18 +1974,46 @@ void ObjectMgr::LoadCreatures() data.phaseMask = 1; } - if (data.phaseGroup && GetPhasesForGroup(data.phaseGroup).empty()) + 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 && !GetPhasesForGroup(data.phaseGroup)) { TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: %u Entry: %u) with non-existing `phasegroup` (%u) set, `phasegroup` set to 0", guid, data.id, data.phaseGroup); data.phaseGroup = 0; } - if (data.phaseGroup && data.phaseid) + if (data.phaseGroup && data.phaseId) { TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u Entry: %u) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.id); 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->rootPhaseMap != 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; @@ -2141,8 +2172,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 17 "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, phaseMask, eventEntry, pool_entry, " - // 18 19 20 - "phaseid, phasegroup, ScriptName " + // 18 19 20 21 22 + "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"); @@ -2243,22 +2274,52 @@ void ObjectMgr::LoadGameobjects() data.phaseMask = fields[15].GetUInt32(); int16 gameEvent = fields[16].GetInt8(); uint32 PoolId = fields[17].GetUInt32(); - data.phaseid = fields[18].GetUInt32(); - data.phaseGroup = fields[19].GetUInt32(); + data.phaseUseFlags = fields[18].GetUInt8(); + data.phaseId = fields[19].GetUInt32(); + data.phaseGroup = fields[20].GetUInt32(); - if (data.phaseGroup && GetPhasesForGroup(data.phaseGroup).empty()) + 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 && !GetPhasesForGroup(data.phaseGroup)) { TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with non-existing `phasegroup` (%u) set, `phasegroup` set to 0", guid, data.id, data.phaseGroup); data.phaseGroup = 0; } - if (data.phaseGroup && data.phaseid) + if (data.phaseGroup && data.phaseId) { TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: %u Entry: %u) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.id); data.phaseGroup = 0; } - data.ScriptId = GetScriptId(fields[20].GetString()); + data.terrainSwapMap = fields[21].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->rootPhaseMap != 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[22].GetString()); if (std::abs(data.orientation) > 2 * float(M_PI)) { @@ -9498,10 +9559,78 @@ void ObjectMgr::LoadFactionChangeTitles() TC_LOG_INFO("server.loading", ">> Loaded %u faction change title pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadPhases() +{ + for (PhaseEntry const* phase : sPhaseStore) + _phaseInfoById.emplace(std::make_pair(phase->ID, PhaseInfoStruct{ phase->ID, std::unordered_set{} })); + + for (MapEntry const* map : sMapStore) + if (map->rootPhaseMap != -1) + _terrainSwapInfoById.emplace(std::make_pair(map->MapID, TerrainSwapInfo{ map->MapID, std::vector{} })); + + 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() +{ + 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 TerrainSwapMap, WorldMapArea FROM `terrain_worldmap`"); + + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 terrain world maps. DB table `terrain_worldmap` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 mapId = fields[0].GetUInt32(); + uint32 worldMapArea = fields[1].GetUInt32(); + + if (!sMapStore.LookupEntry(mapId)) + { + TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_worldmap` does not exist, skipped.", mapId); + continue; + } + + if (!sWorldMapAreaStore.LookupEntry(worldMapArea)) + { + TC_LOG_ERROR("sql.sql", "WorldMapArea %u defined in `terrain_worldmap` does not exist, skipped.", worldMapArea); + continue; + } + + TerrainSwapInfo* terrainSwapInfo = &_terrainSwapInfoById[mapId]; + terrainSwapInfo->Id = mapId; + terrainSwapInfo->UiWorldMapAreaIDSwaps.push_back(worldMapArea); + + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u terrain world maps in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + void ObjectMgr::LoadTerrainSwapDefaults() { - _terrainMapDefaultStore.clear(); - uint32 oldMSTime = getMSTime(); // 0 1 @@ -9534,7 +9663,9 @@ void ObjectMgr::LoadTerrainSwapDefaults() continue; } - _terrainMapDefaultStore[mapId].push_back(terrainSwap); + TerrainSwapInfo* terrainSwapInfo = &_terrainSwapInfoById[terrainSwap]; + terrainSwapInfo->Id = terrainSwap; + _terrainSwapInfoByMap[mapId].push_back(terrainSwapInfo); ++count; } while (result->NextRow()); @@ -9542,88 +9673,8 @@ void ObjectMgr::LoadTerrainSwapDefaults() TC_LOG_INFO("server.loading", ">> Loaded %u terrain swap defaults in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadTerrainPhaseInfo() -{ - _terrainPhaseInfoStore.clear(); - - uint32 oldMSTime = getMSTime(); - - // 0 1 - QueryResult result = WorldDatabase.Query("SELECT Id, TerrainSwapMap FROM `terrain_phase_info`"); - - if (!result) - { - TC_LOG_INFO("server.loading", ">> Loaded 0 terrain phase infos. DB table `terrain_phase_info` is empty."); - return; - } - - uint32 count = 0; - do - { - Field* fields = result->Fetch(); - - uint32 phaseId = fields[0].GetUInt32(); - - PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseId); - if (!phase) - { - TC_LOG_ERROR("sql.sql", "Phase %u defined in `terrain_phase_info` does not exist, skipped.", phaseId); - continue; - } - - uint32 terrainSwap = fields[1].GetUInt32(); - - _terrainPhaseInfoStore[phaseId].push_back(terrainSwap); - - ++count; - } - while (result->NextRow()); - - TC_LOG_INFO("server.loading", ">> Loaded %u terrain phase infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); -} - -void ObjectMgr::LoadTerrainWorldMaps() -{ - _terrainWorldMapStore.clear(); - - uint32 oldMSTime = getMSTime(); - - // 0 1 - QueryResult result = WorldDatabase.Query("SELECT TerrainSwapMap, WorldMapArea FROM `terrain_worldmap`"); - - if (!result) - { - TC_LOG_INFO("server.loading", ">> Loaded 0 terrain world maps. DB table `terrain_worldmap` is empty."); - return; - } - - uint32 count = 0; - do - { - Field* fields = result->Fetch(); - - uint32 mapId = fields[0].GetUInt32(); - - if (!sMapStore.LookupEntry(mapId)) - { - TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_worldmap` does not exist, skipped.", mapId); - continue; - } - - uint32 worldMapArea = fields[1].GetUInt32(); - - _terrainWorldMapStore[mapId].push_back(worldMapArea); - - ++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(); - uint32 oldMSTime = getMSTime(); // 0 1 @@ -9635,23 +9686,93 @@ void ObjectMgr::LoadAreaPhases() return; } + auto getOrCreatePhaseIfMissing = [this](uint32 phaseId) + { + PhaseInfoStruct* phaseInfo = &_phaseInfoById[phaseId]; + phaseInfo->Id = phaseId; + return phaseInfo; + }; + uint32 count = 0; do { Field* fields = result->Fetch(); - - PhaseInfoStruct phase; uint32 area = fields[0].GetUInt32(); + uint32 phaseId = fields[1].GetUInt32(); + if (!sAreaTableStore.LookupEntry(area)) + { + TC_LOG_ERROR("sql.sql", "Area %u defined in `phase_area` does not exist, skipped.", area); + continue; + } - phase.Id = fields[1].GetUInt32(); - _phases[area].push_back(phase); + if (!sPhaseStore.LookupEntry(phaseId)) + { + TC_LOG_ERROR("sql.sql", "Phase %u defined in `phase_area` does not exist, skipped.", phaseId); + continue; + } + + PhaseInfoStruct* phase = getOrCreatePhaseIfMissing(phaseId); + phase->Areas.insert(area); + _phaseInfoByArea[area].emplace_back(phase); ++count; } while (result->NextRow()); + 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; + + parentAreaId = area->zone; + if (!parentAreaId) + break; + + if (std::vector* parentAreaPhases = Trinity::Containers::MapGetValuePtr(_phaseInfoByArea, parentAreaId)) + for (PhaseAreaInfo& parentAreaPhase : *parentAreaPhases) + if (parentAreaPhase.PhaseInfo->Id == phase.PhaseInfo->Id) + parentAreaPhase.SubAreaExclusions.insert(itr->first); + + } while (true); + } + } + 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) + { + return IsInArea(areaId, areaToCheck); + }); +} + +PhaseInfoStruct const* ObjectMgr::GetPhaseInfo(uint32 phaseId) const +{ + return Trinity::Containers::MapGetValuePtr(_phaseInfoById, phaseId); +} + +std::vector const* ObjectMgr::GetPhasesForArea(uint32 areaId) const +{ + return Trinity::Containers::MapGetValuePtr(_phaseInfoByArea, areaId); +} + +TerrainSwapInfo const* ObjectMgr::GetTerrainSwapInfo(uint32 terrainSwapId) const +{ + return Trinity::Containers::MapGetValuePtr(_terrainSwapInfoById, terrainSwapId); +} + +std::vector const* ObjectMgr::GetTerrainSwapsForMap(uint32 mapId) const +{ + return Trinity::Containers::MapGetValuePtr(_terrainSwapInfoByMap, mapId); +} + GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry) const { GameObjectTemplateContainer::const_iterator itr = _gameObjectTemplateStore.find(entry); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 3c16a08136b..e04baf7b522 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -710,15 +710,28 @@ struct HotfixInfo typedef std::vector HotfixData; +struct TerrainSwapInfo +{ + uint32 Id; + std::vector UiWorldMapAreaIDSwaps; +}; + struct PhaseInfoStruct { uint32 Id; - ConditionContainer Conditions; + std::unordered_set Areas; + + bool IsAllowedInArea(uint32 areaId) const; }; -typedef std::unordered_map> TerrainPhaseInfo; // terrain swap -typedef std::unordered_map> TerrainUIPhaseInfo; // worldmaparea swap -typedef std::unordered_map> PhaseInfo; // phase +struct PhaseAreaInfo +{ + PhaseAreaInfo(PhaseInfoStruct const* phaseInfo) : PhaseInfo(phaseInfo) { } + + PhaseInfoStruct const* PhaseInfo; + std::unordered_set SubAreaExclusions; + ConditionContainer Conditions; +}; class PlayerDumpReader; @@ -1066,7 +1079,8 @@ class TC_GAME_API ObjectMgr void LoadTrainerSpell(); void AddSpellToTrainer(uint32 ID, uint32 SpellID, uint32 MoneyCost, uint32 ReqSkillLine, uint32 ReqSkillRank, uint32 ReqLevel, uint32 Index); - void LoadTerrainPhaseInfo(); + void LoadPhases(); + void UnloadPhaseConditions(); void LoadTerrainSwapDefaults(); void LoadTerrainWorldMaps(); void LoadAreaPhases(); @@ -1338,36 +1352,6 @@ class TC_GAME_API ObjectMgr return _gossipMenuItemsStore.equal_range(uiMenuId); } - std::vector const* GetPhaseTerrainSwaps(uint32 phaseid) const - { - auto itr = _terrainPhaseInfoStore.find(phaseid); - return itr != _terrainPhaseInfoStore.end() ? &itr->second : nullptr; - } - std::vector const* GetDefaultTerrainSwaps(uint32 mapid) const - { - auto itr = _terrainMapDefaultStore.find(mapid); - return itr != _terrainMapDefaultStore.end() ? &itr->second : nullptr; - } - std::vector const* GetTerrainWorldMaps(uint32 terrainId) const - { - auto itr = _terrainWorldMapStore.find(terrainId); - return itr != _terrainWorldMapStore.end() ? &itr->second : nullptr; - } - std::vector 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& GetAreaPhases() const { return _phases; } - // condition loading helpers - std::vector* GetPhasesForAreaForLoading(uint32 area) - { - auto itr = _phases.find(area); - return itr != _phases.end() ? &itr->second : nullptr; - } - PhaseInfo& GetAreaPhasesForLoading() { return _phases; } - // for wintergrasp only GraveYardContainer GraveYardStore; @@ -1486,10 +1470,18 @@ 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 const* GetPhasesForArea(uint32 areaId) const; + TerrainSwapInfo const* GetTerrainSwapInfo(uint32 terrainSwapId) const; + std::vector const* GetTerrainSwapsForMap(uint32 mapId) const; + + private: + std::unordered_map _phaseInfoById; + std::unordered_map _terrainSwapInfoById; + std::unordered_map> _phaseInfoByArea; + std::unordered_map> _terrainSwapInfoByMap; + private: void LoadScripts(ScriptsType type); diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index 3ff20024d37..4039915efed 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -324,7 +324,7 @@ void MessageDistDelivererToHostile::Visit(PlayerMapType &m) for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { Player* target = iter->GetSource(); - if (!target->IsInPhase(i_phaseMask)) + if (!target->IsInPhase(i_source)) continue; if (target->GetExactDist2dSq(i_source) > i_distSq) @@ -349,7 +349,7 @@ void MessageDistDelivererToHostile::Visit(CreatureMapType &m) for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { Creature* target = iter->GetSource(); - if (!target->IsInPhase(i_phaseMask)) + if (!target->IsInPhase(i_source)) continue; if (target->GetExactDist2dSq(i_source) > i_distSq) @@ -371,7 +371,7 @@ void MessageDistDelivererToHostile::Visit(DynamicObjectMapType &m) for (DynamicObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { DynamicObject* target = iter->GetSource(); - if (!target->IsInPhase(i_phaseMask)) + if (!target->IsInPhase(i_source)) continue; if (target->GetExactDist2dSq(i_source) > i_distSq) diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index 688f100e408..b24efc2cfa6 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -24,6 +24,7 @@ #include "Log.h" #include "ObjectMgr.h" #include "Pet.h" +#include "PhasingHandler.h" #include "Player.h" #include "SocialMgr.h" #include "SpellAuras.h" @@ -984,8 +985,6 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacke if (mask == GROUP_UPDATE_FLAG_NONE) return; - std::set const& phases = player->GetPhases(); - if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); @@ -1207,12 +1206,7 @@ void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacke } if (mask & GROUP_UPDATE_FLAG_PHASE) - { - *data << uint32(phases.empty() ? 8 : 0); - *data << uint32(phases.size()); - for (std::set::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - *data << uint16(*itr); - } + PhasingHandler::FillPartyMemberPhase(data, player->GetPhaseShift()); } /*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ @@ -1236,7 +1230,6 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData) Pet* pet = player->GetPet(); Powers powerType = player->getPowerType(); - std::set const& phases = player->GetPhases(); WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8); data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related @@ -1257,7 +1250,7 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData) if (player->GetVehicle()) updateFlags |= GROUP_UPDATE_FLAG_VEHICLE_SEAT; - if (!phases.empty()) + if (!player->GetPhaseShift().GetPhases().empty()) updateFlags |= GROUP_UPDATE_FLAG_PHASE; uint16 playerStatus = MEMBER_STATUS_ONLINE; @@ -1385,12 +1378,7 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData) data << uint32(player->GetVehicle()->GetVehicleInfo()->m_seatID[player->m_movementInfo.transport.seat]); if (updateFlags & GROUP_UPDATE_FLAG_PHASE) - { - data << uint32(phases.empty() ? 8 : 0); - data << uint32(phases.size()); - for (std::set::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - data << uint16(*itr); - } + PhasingHandler::FillPartyMemberPhase(&data, player->GetPhaseShift()); SendPacket(&data); } diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index b7b0c0dede4..48e84d71421 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1603,54 +1603,6 @@ void WorldSession::HandleReadyForAccountDataTimes(WorldPacket& /*recvData*/) SendAccountDataTimes(GLOBAL_CACHE_MASK); } -void WorldSession::SendSetPhaseShift(std::set const& phaseIds, std::set const& terrainswaps, std::set const& worldMapAreaSwaps) -{ - ObjectGuid guid = _player->GetGUID(); - - WorldPacket data(SMSG_SET_PHASE_SHIFT, 1 + 8 + 4 + 4 + 4 + 4 + 2 * phaseIds.size() + 4 + terrainswaps.size() * 2); - data.WriteBit(guid[2]); - data.WriteBit(guid[3]); - data.WriteBit(guid[1]); - data.WriteBit(guid[6]); - data.WriteBit(guid[4]); - data.WriteBit(guid[5]); - data.WriteBit(guid[0]); - data.WriteBit(guid[7]); - - data.WriteByteSeq(guid[7]); - data.WriteByteSeq(guid[4]); - - data << uint32(worldMapAreaSwaps.size()) * 2; - for (auto mapSwap : worldMapAreaSwaps) - data << uint16(mapSwap); // WorldMapArea.dbc id (controls map display) - - data.WriteByteSeq(guid[1]); - - data << uint32(phaseIds.size() ? 0 : 8); // flags (not phasemask) - - data.WriteByteSeq(guid[2]); - data.WriteByteSeq(guid[6]); - - data << uint32(0); // Inactive terrain swaps - //for (uint8 i = 0; i < inactiveSwapsCount; ++i) - // data << uint16(0); - - data << uint32(phaseIds.size()) * 2; // Phase.dbc ids - for (std::set::const_iterator itr = phaseIds.begin(); itr != phaseIds.end(); ++itr) - data << uint16(*itr); - - data.WriteByteSeq(guid[3]); - data.WriteByteSeq(guid[0]); - - data << uint32(terrainswaps.size()) * 2; // Active terrain swaps - for (std::set::const_iterator itr = terrainswaps.begin(); itr != terrainswaps.end(); ++itr) - data << uint16(*itr); - - data.WriteByteSeq(guid[5]); - - SendPacket(&data); -} - // Battlefield and Battleground void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPacket& recvData) { diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index 50737883200..618e73295bb 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -266,7 +266,7 @@ void WorldSession::HandleCorpseQueryOpcode(WorldPacket& /*recvData*/) mapID = corpseMapEntry->entrance_map; x = corpseMapEntry->entrance_x; y = corpseMapEntry->entrance_y; - z = entranceMap->GetHeight(GetPlayer()->GetPhases(), x, y, MAX_HEIGHT); + z = entranceMap->GetHeight(GetPlayer()->GetPhaseShift(), x, y, MAX_HEIGHT); } } } diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 3a38c41bfae..2290fe42f48 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -27,6 +27,7 @@ #include "Map.h" #include "Player.h" #include "Pet.h" +#include "PhasingHandler.h" #include "WorldSession.h" #include "Opcodes.h" #include "ScriptReloadMgr.h" @@ -713,7 +714,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); } void InstanceScript::UpdateCombatResurrection(uint32 diff) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 22a7bc098df..bfde82d670a 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -31,6 +31,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Pet.h" +#include "PhasingHandler.h" #include "ScriptMgr.h" #include "Transport.h" #include "Vehicle.h" @@ -536,8 +537,7 @@ bool Map::AddPlayerToMap(Player* player) player->m_clientGUIDs.clear(); player->UpdateObjectVisibility(false); - - player->SendUpdatePhasing(); + PhasingHandler::SendToPlayer(player); if (player->IsAlive()) ConvertCorpseToBones(player->GetGUID()); @@ -600,8 +600,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(); @@ -2239,12 +2237,12 @@ inline GridMap* Map::GetGrid(float x, float y) return GridMaps[gx][gy]; } -float Map::GetWaterOrGroundLevel(std::set 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(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; @@ -2629,24 +2627,24 @@ 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 const& phases, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const +bool Map::isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const { if ((checks & LINEOFSIGHT_CHECK_VMAP) && !VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2, ignoreFlags)) return false; if (sWorld->getBoolConfig(CONFIG_CHECK_GOBJECT_LOS) && (checks & LINEOFSIGHT_CHECK_GOBJECT) - && !_dynamicTree.isInLineOfSight({x1, y1, z1}, {x2, y2, z2}, phases)) + && !_dynamicTree.isInLineOfSight({x1, y1, z1}, {x2, y2, z2}, phaseShift)) return false; return true; } -bool Map::getObjectHitPos(std::set 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; @@ -2654,9 +2652,9 @@ bool Map::getObjectHitPos(std::set const& phases, float x1, float y1, fl return result; } -float Map::GetHeight(std::set 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(GetHeight(x, y, z, vmap, maxSearchDist), GetGameObjectFloor(phases, x, y, z, maxSearchDist)); + return std::max(GetHeight(x, y, z, vmap, maxSearchDist), GetGameObjectFloor(phaseShift, x, y, z, maxSearchDist)); } bool Map::IsInWater(float x, float y, float pZ, LiquidData* data) const @@ -2703,6 +2701,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) @@ -2710,9 +2709,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); @@ -2723,9 +2722,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); @@ -2736,28 +2740,33 @@ 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 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); + if (player->IsInPhase(transport)) + { + if (player->m_visibleTransports.find(transport->GetGUID()) == player->m_visibleTransports.end()) + transport->BuildCreateUpdateBlockForPlayer(&transData, player); + } + else if (player->m_visibleTransports.find(transport->GetGUID()) != player->m_visibleTransports.end()) + transport->BuildOutOfRangeUpdateBlock(&transData); } WorldPacket packet; @@ -3775,8 +3784,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); } while (result->NextRow()); @@ -3861,7 +3870,7 @@ Corpse* Map::ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia /*= if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i)) bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0); - 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 d42cb18a6ee..e4c6c50c0fa 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -42,6 +42,7 @@ class InstanceScript; class Group; class InstanceSave; class Object; +class PhaseShift; class WorldObject; class TempSummon; class Player; @@ -514,18 +515,18 @@ class TC_GAME_API Map : public GridRefManager BattlegroundMap* ToBattlegroundMap() { if (IsBattlegroundOrArena()) return reinterpret_cast(this); else return NULL; } BattlegroundMap const* ToBattlegroundMap() const { if (IsBattlegroundOrArena()) return reinterpret_cast(this); return NULL; } - float GetWaterOrGroundLevel(std::set const& phases, float x, float y, float z, float* ground = nullptr, bool swim = false) const; - float GetHeight(std::set 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 const& phases, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const; + float GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground = nullptr, bool swim = false) const; + float GetHeight(PhaseShift const& phaseShifts, 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, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) 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);} - float GetGameObjectFloor(std::set phases, float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const + float GetGameObjectFloor(PhaseShift const& phaseShift, float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const { - return _dynamicTree.getHeight(x, y, z, maxSearchDist, phases); + return _dynamicTree.getHeight(x, y, z, maxSearchDist, phaseShift); } - bool getObjectHitPos(std::set 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 uint32 GetOwnerGuildId(uint32 /*team*/ = TEAM_OTHER) const { return 0; } /* @@ -568,7 +569,7 @@ class TC_GAME_API Map : public GridRefManager void SendInitTransports(Player* player); void SendRemoveTransports(Player* player); - void SendUpdateTransportVisibility(Player* player, std::set const& previousPhases); + void SendUpdateTransportVisibility(Player* player); void SendZoneDynamicInfo(Player* player); void SetZoneMusic(uint32 zoneId, uint32 musicId); diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index cd3bdb5902c..2b096d9c5bd 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -20,6 +20,7 @@ #include "InstanceScript.h" #include "MoveSpline.h" #include "MapManager.h" +#include "PhasingHandler.h" TransportTemplate::~TransportTemplate() { @@ -354,7 +355,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) @@ -395,12 +396,7 @@ Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid return NULL; } - if (phaseid) - trans->SetInPhase(phaseid, false, true); - - if (phasegroup) - for (auto ph : GetPhasesForGroup(phasegroup)) - trans->SetInPhase(ph, false, true); + PhasingHandler::InitDbPhaseShift(trans->GetPhaseShift(), phaseUseFlags, phaseId, phaseGroupId); if (MapEntry const* mapEntry = sMapStore.LookupEntry(mapId)) { @@ -431,7 +427,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) @@ -441,12 +437,50 @@ void TransportMgr::SpawnContinentTransports() Field* fields = result->Fetch(); ObjectGuid::LowType guid = fields[0].GetUInt32(); 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 (!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 4038d213b38..14025b0fc3c 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -108,7 +108,7 @@ class TC_GAME_API TransportMgr void LoadTransportTemplates(); // Creates a transport using given GameObject template entry - Transport* CreateTransport(uint32 entry, ObjectGuid::LowType guid = 0, Map* map = nullptr, uint32 phaseid = 0, uint32 phasegroup = 0); + Transport* CreateTransport(uint32 entry, ObjectGuid::LowType guid = 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 d4440de644d..1b9781c91e4 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -213,7 +213,13 @@ enum TrinityStrings LANG_INVALID_GAMEOBJECT_TYPE = 176, LANG_GAMEOBJECT_DAMAGED = 177, LANG_GRID_POSITION = 178, - // 179-185 used in 6.x branch + 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, + // 185 not used LANG_TRANSPORT_POSITION = 186, LANG_PARTIAL_GROUP_SUMMON = 187, // Room for more level 1 188-199 not used diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 0a0a0a90399..418d0ff945c 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -486,7 +486,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); } @@ -569,7 +569,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 d2379f806a6..8bd2b5dc9ea 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -63,7 +63,7 @@ void RandomMovementGenerator::_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) @@ -77,17 +77,17 @@ void RandomMovementGenerator::_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..cfeaf61c199 --- /dev/null +++ b/src/server/game/Phasing/PhaseShift.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2008-2018 TrinityCore + * + * 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 . + */ + +#include "PhaseShift.h" +#include "Containers.h" + +bool PhaseShift::AddPhase(uint32 phaseId, PhaseFlags flags, PhaseInfoStruct const* phase, std::vector const* areaConditions, int32 references /*= 1*/) +{ + auto insertResult = Phases.emplace(phaseId, flags, phase, nullptr); + ModifyPhasesReferences(insertResult.first, references); + if (areaConditions) + insertResult.first->AreaConditions = areaConditions; + + return insertResult.second; +} + +PhaseShift::EraseResult PhaseShift::RemovePhase(uint32 phaseId) +{ + auto itr = Phases.find(PhaseRef(phaseId, PhaseFlags::None, nullptr, 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::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::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::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::NoCosmetic); + + UpdateUnphasedFlag(); + } +} + +void PhaseShift::UpdateUnphasedFlag() +{ + EnumClassFlag unphasedFlag = !Flags.HasFlag(PhaseShiftFlags::Inverse) ? PhaseShiftFlags::Unphased : PhaseShiftFlags::InverseUnphased; + Flags &= ~EnumClassFlag(!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..7576af4a9c5 --- /dev/null +++ b/src/server/game/Phasing/PhaseShift.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008-2018 TrinityCore + * + * 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 . + */ + +#ifndef PhaseShift_h__ +#define PhaseShift_h__ + +#include "Define.h" +#include "EnumClassFlag.h" +#include "ObjectGuid.h" +#include +#include + +class PhasingHandler; +struct Condition; +struct PhaseInfoStruct; +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, PhaseInfoStruct const* phaseInfo, std::vector const* conditions) + : Id(id), Flags(flags), References(0), PhaseInfo(phaseInfo), AreaConditions(conditions) { } + + uint16 Id; + EnumClassFlag Flags; + int32 References; + PhaseInfoStruct const* PhaseInfo; + std::vector 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 + struct EraseResult + { + typename Container::iterator Iterator; + bool Erased; + }; + typedef boost::container::flat_set PhaseContainer; + typedef std::map VisibleMapIdContainer; + typedef std::map UiWorldMapAreaIdSwapContainer; + + bool AddPhase(uint32 phaseId, PhaseFlags flags, PhaseInfoStruct const* phase, std::vector const* areaConditions, int32 references = 1); + EraseResult RemovePhase(uint32 phaseId); + bool HasPhase(uint32 phaseId) const { return Phases.find(PhaseRef(phaseId, PhaseFlags::None, nullptr, nullptr)) != Phases.end(); } + PhaseContainer const& GetPhases() const { return Phases; } + + bool AddVisibleMapId(uint32 visibleMapId, TerrainSwapInfo const* visibleMapInfo, int32 references = 1); + EraseResult 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 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 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..1190b4b7427 --- /dev/null +++ b/src/server/game/Phasing/PhasingHandler.cpp @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2008-2018 TrinityCore + * + * 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 . + */ + +#include "PhasingHandler.h" +#include "Chat.h" +#include "ConditionMgr.h" +#include "Creature.h" +#include "DBCStores.h" +#include "Language.h" +#include "Map.h" +#include "ObjectMgr.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 +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), sObjectMgr->GetPhaseInfo(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 const* phasesInGroup = GetPhasesForGroup(phaseGroupId); + if (!phasesInGroup) + return; + + bool changed = false; + for (uint32 phaseId : *phasesInGroup) + changed = object->GetPhaseShift().AddPhase(phaseId, GetPhaseFlags(phaseId), sObjectMgr->GetPhaseInfo(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 const* phasesInGroup = 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 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(); + + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(object->GetAreaId()); + while (areaEntry) + { + if (std::vector const* newAreaPhases = sObjectMgr->GetPhasesForArea(areaEntry->ID)) + { + for (PhaseAreaInfo const& phaseArea : *newAreaPhases) + { + if (phaseArea.SubAreaExclusions.find(areaEntry->ID) != phaseArea.SubAreaExclusions.end()) + continue; + + uint32 phaseId = phaseArea.PhaseInfo->Id; + if (sConditionMgr->IsObjectMeetToConditions(srcInfo, phaseArea.Conditions)) + phaseShift.AddPhase(phaseArea.PhaseInfo->Id, GetPhaseFlags(phaseId), phaseArea.PhaseInfo, &phaseArea.Conditions); + else + suppressedPhaseShift.AddPhase(phaseArea.PhaseInfo->Id, GetPhaseFlags(phaseId), phaseArea.PhaseInfo, &phaseArea.Conditions); + } + } + + areaEntry = sAreaTableStore.LookupEntry(areaEntry->zone); + } + + 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), sObjectMgr->GetPhaseInfo(phaseId), nullptr) || changed; + } + + for (AuraEffect const* aurEff : unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP)) + if (std::vector const* phasesInGroup = GetPhasesForGroup(uint32(aurEff->GetMiscValueB()))) + for (uint32 phaseId : *phasesInGroup) + changed = phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), sObjectMgr->GetPhaseInfo(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 (!sConditionMgr->IsObjectMeetToConditions(srcInfo, *itr->AreaConditions)) + { + newSuppressions.AddPhase(itr->Id, itr->Flags, itr->PhaseInfo, 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, *itr->AreaConditions)) + { + changed = phaseShift.AddPhase(itr->Id, itr->Flags, itr->PhaseInfo, 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()); + phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), sObjectMgr->GetPhaseInfo(phaseId), nullptr); + newSuppressions.RemovePhase(phaseId); + } + + for (AuraEffect const* aurEff : unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP)) + { + if (std::vector const* phasesInGroup = GetPhasesForGroup(uint32(aurEff->GetMiscValueB()))) + { + for (uint32 phaseId : *phasesInGroup) + { + phaseShift.AddPhase(phaseId, GetPhaseFlags(phaseId), sObjectMgr->GetPhaseInfo(phaseId), nullptr); + newSuppressions.RemovePhase(phaseId); + } + } + } + } + + 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->PhaseInfo, 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) +{ + ObjectGuid guid = player->GetGUID(); + + WorldPacket data(SMSG_SET_PHASE_SHIFT, 1 + 8 + 4 + 4 + 4 + 4 + 2 * phaseShift.Phases.size() + 4 + phaseShift.VisibleMapIds.size() * 2); + data.WriteBit(guid[2]); + data.WriteBit(guid[3]); + data.WriteBit(guid[1]); + data.WriteBit(guid[6]); + data.WriteBit(guid[4]); + data.WriteBit(guid[5]); + data.WriteBit(guid[0]); + data.WriteBit(guid[7]); + + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[4]); + + data << uint32(phaseShift.UiWorldMapAreaIdSwaps.size()) * 2; + for (auto itr = phaseShift.UiWorldMapAreaIdSwaps.begin(); itr != phaseShift.UiWorldMapAreaIdSwaps.end(); ++itr) + data << uint16(itr->first); // WorldMapArea.dbc id (controls map display) + + data.WriteByteSeq(guid[1]); + + data << uint32(phaseShift.Flags.AsUnderlyingType()); // flags + + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[6]); + + data << uint32(0); // Inactive terrain swaps + //for (uint8 i = 0; i < inactiveSwapsCount; ++i) + // data << uint16(0); + + data << uint32(phaseShift.Phases.size()) * 2; // Phase.dbc ids + for (auto itr = phaseShift.Phases.begin(); itr != phaseShift.Phases.end(); ++itr) + data << uint16(itr->Id); + + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[0]); + + data << uint32(phaseShift.VisibleMapIds.size()) * 2; // Active terrain swaps + for (auto itr = phaseShift.VisibleMapIds.begin(); itr != phaseShift.VisibleMapIds.end(); ++itr) + data << uint16(itr->first); + + data.WriteByteSeq(guid[5]); + + player->SendDirectMessage(&data); +} + +void PhasingHandler::SendToPlayer(Player const* player) +{ + SendToPlayer(player, player->GetPhaseShift()); +} + +void PhasingHandler::FillPartyMemberPhase(WorldPacket* data, PhaseShift const& phaseShift) +{ + *data << uint32(phaseShift.Flags.AsUnderlyingType()); + *data << uint32(phaseShift.Phases.size()); + for (auto itr = phaseShift.Phases.begin(); itr != phaseShift.Phases.end(); ++itr) + *data << uint16(itr->Id); +} + +void PhasingHandler::InitDbPhaseShift(PhaseShift& phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId) +{ + phaseShift.IsDbPhaseShift = true; + + EnumClassFlag 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), sObjectMgr->GetPhaseInfo(phaseId), nullptr); + else if (std::vector const* phasesInGroup = GetPhasesForGroup(phaseGroupId)) + for (uint32 phaseInGroup : *phasesInGroup) + phaseShift.AddPhase(phaseInGroup, GetPhaseFlags(phaseInGroup), sObjectMgr->GetPhaseInfo(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::AlwaysVisible); +} + +void PhasingHandler::SetInversed(PhaseShift& phaseShift, bool apply) +{ + if (apply) + phaseShift.Flags |= PhaseShiftFlags::Inverse; + else + phaseShift.Flags &= ~EnumClassFlag(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..1c6bf117889 --- /dev/null +++ b/src/server/game/Phasing/PhasingHandler.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008-2018 TrinityCore + * + * 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 . + */ + +#ifndef PhasingHandler_h__ +#define PhasingHandler_h__ + +#include "Define.h" +#include + +class ChatHandler; +class PhaseShift; +class Player; +class WorldObject; + +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(WorldPacket* data, 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/WorldSession.h b/src/server/game/Server/WorldSession.h index f7b34b5e249..8ac314fc552 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -298,7 +298,6 @@ class TC_GAME_API WorldSession void SendPetNameInvalid(uint32 error, std::string const& name, DeclinedName *declinedName); void SendPartyResult(PartyOperation operation, std::string const& member, PartyResult res, uint32 val = 0); void SendAreaTriggerMessage(const char* Text, ...) ATTR_PRINTF(2, 3); - void SendSetPhaseShift(std::set const& phaseIds, std::set const& terrainswaps, std::set const& worldMapAreaSwaps); void SendQueryTimeResponse(); void SendAuthResponse(uint8 code, bool queued, uint32 queuePos = 0); diff --git a/src/server/game/Skills/Archaeology/ArchaeologySites.cpp b/src/server/game/Skills/Archaeology/ArchaeologySites.cpp index 23be86a883f..ec1edcf7ba3 100644 --- a/src/server/game/Skills/Archaeology/ArchaeologySites.cpp +++ b/src/server/game/Skills/Archaeology/ArchaeologySites.cpp @@ -119,7 +119,7 @@ void Archaeology::UseSite() float x = _player->GetPositionX() + cos(o) * 2.0f; float y = _player->GetPositionY() + sin(o) * 2.0f; float z = _player->GetPositionZ(); - float ground = _player->GetMap()->GetWaterOrGroundLevel(_player->GetPhases(), x, y, z, &ground, _player->IsInWater()); + float ground = _player->GetMap()->GetWaterOrGroundLevel(_player->GetPhaseShift(), x, y, z, &ground, _player->IsInWater()); G3D::Quat rot = G3D::Matrix3::fromEulerAnglesZYX(angle, 0.f, 0.f); if (std::abs(z - ground) < 1.5f) @@ -140,7 +140,7 @@ void Archaeology::UseSite() float x = _player->GetPositionX() + cos(o) * 2.0f; float y = _player->GetPositionY() + sin(o) * 2.0f; float z = _player->GetPositionZ(); - float ground = _player->GetMap()->GetWaterOrGroundLevel(_player->GetPhases(), x, y, z, &ground, _player->IsInWater()); + float ground = _player->GetMap()->GetWaterOrGroundLevel(_player->GetPhaseShift(), x, y, z, &ground, _player->IsInWater()); // Spawn object _player->SummonGameObject(goId, Position(x, y, ground, o), G3D::Quat(), 60); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 6b75f2eeb1f..7f39a3992a4 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -22,6 +22,7 @@ #include "Log.h" #include "ObjectMgr.h" #include "SpellMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "Unit.h" #include "ObjectAccessor.h" @@ -1703,8 +1704,7 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app Unit* target = aurApp->GetTarget(); - std::set const& oldPhases = target->GetPhases(); - target->SetInPhase(GetMiscValueB(), false, 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 @@ -1713,17 +1713,6 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app // 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(); } void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -1733,10 +1722,7 @@ void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, boo Unit* target = aurApp->GetTarget(); - std::set const& oldPhases = target->GetPhases(); - std::set const& phases = GetPhasesForGroup(GetMiscValueB()); - for (auto phase : phases) - target->SetInPhase(phase, false, 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 @@ -1745,17 +1731,6 @@ void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, boo // 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(); } /**********************/ diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index a5a0f23725c..0acebd94256 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1303,7 +1303,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici float angle = float(rand_norm()) * static_cast(M_PI * 35.0f / 180.0f) - static_cast(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 406de6f7225..3ebcfefb607 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -25,6 +25,7 @@ #include "World.h" #include "ObjectMgr.h" #include "SpellMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "SkillExtraItems.h" #include "Unit.h" @@ -3165,7 +3166,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) return; } - pGameObj->CopyPhaseFrom(m_caster); + PhasingHandler::InheritPhaseShift(pGameObj, m_caster); int32 duration = m_spellInfo->GetDuration(); @@ -3184,6 +3185,8 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) if (GameObject* linkedTrap = pGameObj->GetLinkedTrap()) { + PhasingHandler::InheritPhaseShift(linkedTrap, m_caster); + linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0); linkedTrap->SetSpellId(m_spellInfo->Id); @@ -3773,7 +3776,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex) return; } - pGameObj->CopyPhaseFrom(m_caster); + PhasingHandler::InheritPhaseShift(pGameObj, m_caster); pGameObj->SetFaction(m_caster->GetFaction()); pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1); @@ -4134,7 +4137,7 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex) return; } - go->CopyPhaseFrom(m_caster); + PhasingHandler::InheritPhaseShift(go, m_caster); //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); int32 duration = m_spellInfo->GetDuration(); @@ -4848,7 +4851,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) return; } - pGameObj->CopyPhaseFrom(m_caster); + PhasingHandler::InheritPhaseShift(pGameObj, m_caster); int32 duration = m_spellInfo->GetDuration(); @@ -4908,6 +4911,8 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) if (GameObject* linkedTrap = pGameObj->GetLinkedTrap()) { + PhasingHandler::InheritPhaseShift(linkedTrap, m_caster); + linkedTrap->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); //linkedTrap->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); linkedTrap->SetSpellId(m_spellInfo->Id); @@ -5742,7 +5747,7 @@ void Spell::EffectUpdatePlayerPhase(SpellEffIndex /*effIndex*/) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - unitTarget->UpdateAreaPhase(); + 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 008d1f13aaa..b364a6136d3 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1885,17 +1885,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 c454957e1f2..d2e607d79f1 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -24,6 +24,7 @@ EndScriptData */ #include "ScriptMgr.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "BattlefieldMgr.h" #include "BattlegroundMgr.h" #include "Chat.h" @@ -979,7 +980,7 @@ public: return false; } - v->CopyPhaseFrom(handler->GetSession()->GetPlayer()); + PhasingHandler::InheritPhaseShift(v, handler->GetSession()->GetPlayer()); map->AddToMap(v->ToCreature()); @@ -1008,22 +1009,20 @@ public: if (!t) return false; - std::set terrainswap; - std::set phaseId; - std::set 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, 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; } @@ -1462,15 +1461,8 @@ public: std::stringstream phases; - for (uint32 phase : target->GetPhases()) - { - phases << phase << " "; - } + PhasingHandler::PrintToChat(handler, target->GetPhaseShift()); - if (!phases.str().empty()) - handler->PSendSysMessage("Target's current phases: %s", phases.str().c_str()); - else - handler->SendSysMessage("Target is not phased"); return true; } diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 3ad09017315..620b626aa8e 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -31,6 +31,7 @@ EndScriptData */ #include "Language.h" #include "Player.h" #include "Opcodes.h" +#include "PhasingHandler.h" class gobject_commandscript : public CommandScript { @@ -147,7 +148,7 @@ public: 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 e65e21728c9..34114729807 100644 --- a/src/server/scripts/Commands/cs_group.cpp +++ b/src/server/scripts/Commands/cs_group.cpp @@ -21,6 +21,7 @@ #include "LFG.h" #include "Player.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "GroupMgr.h" #include "ScriptMgr.h" @@ -331,7 +332,6 @@ public: { // Get ALL the variables! Player* playerTarget; - uint32 phase = 0; ObjectGuid guidTarget; std::string nameTarget; std::string zoneName; @@ -412,11 +412,12 @@ public: // Check if iterator is online. If is... Player* p = ObjectAccessor::FindPlayer((*itr).guid); + std::string phases; if (p) { // ... than, it prints information like "is online", where he is, etc... onlineState = "online"; - phase = (!p->IsGameMaster() ? p->GetPhaseMask() : -1); + phases = PhasingHandler::FormatPhases(p->GetPhaseShift()); LocaleConstant localeConstant = handler->GetSessionDbcLocale(); AreaTableEntry const* area = sAreaTableStore.LookupEntry(p->GetAreaId()); @@ -432,12 +433,11 @@ public: // ... else, everything is set to offline or neutral values. zoneName = ""; onlineState = "Offline"; - phase = 0; } // Now we can print those informations for every single member of each group! handler->PSendSysMessage(LANG_GROUP_PLAYER_NAME_GUID, slot.name.c_str(), onlineState, - zoneName.c_str(), phase, slot.guid.GetCounter(), flags.c_str(), + zoneName.c_str(), phases.c_str(), slot.guid.GetCounter(), flags.c_str(), lfg::GetRolesString(slot.roles).c_str()); } diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 61f69d9c9d0..0e7ad943fb6 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -32,6 +32,7 @@ #include "WeatherMgr.h" #include "Player.h" #include "Pet.h" +#include "PhasingHandler.h" #include "LFG.h" #include "GroupMgr.h" #include "MMapFactory.h" @@ -238,8 +239,8 @@ public: Map2ZoneCoordinates(zoneX, zoneY, zoneId); 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()); @@ -266,7 +267,6 @@ public: mapId, (mapEntry ? mapEntry->name : unknown), zoneId, (zoneEntry ? zoneEntry->area_name : unknown), areaId, (areaEntry ? areaEntry->area_name : unknown), - object->GetPhaseMask(), StringJoin(object->GetPhases(), ", ").c_str(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation()); if (Transport* transport = object->GetTransport()) handler->PSendSysMessage(LANG_TRANSPORT_POSITION, @@ -282,20 +282,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; } @@ -453,8 +440,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 { @@ -584,7 +571,8 @@ public: float x, y, z; _player->GetClosePoint(x, y, z, target->GetObjectSize()); target->TeleportTo(_player->GetMapId(), x, y, z, target->GetOrientation()); - target->SetPhaseMask(_player->GetPhaseMask(), true); + PhasingHandler::InheritPhaseShift(target, handler->GetSession()->GetPlayer()); + target->UpdateObjectVisibility(); } else { @@ -1611,7 +1599,6 @@ public: // Position data print uint32 mapId; uint32 areaId; - std::set phases; std::string areaName = handler->GetTrinityString(LANG_UNKNOWN); std::string zoneName = handler->GetTrinityString(LANG_UNKNOWN); @@ -1643,7 +1630,6 @@ public: areaId = target->GetAreaId(); alive = target->IsAlive() ? handler->GetTrinityString(LANG_YES) : handler->GetTrinityString(LANG_NO); gender = target->getGender(); - phases = target->GetPhases(); } // get additional information from DB else @@ -1830,9 +1816,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 d7a8f3e2ca4..0f30a37d782 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -27,6 +27,7 @@ EndScriptData */ #include "ObjectMgr.h" #include "Opcodes.h" #include "Pet.h" +#include "PhasingHandler.h" #include "Player.h" #include "ReputationMgr.h" #include "ScriptMgr.h" @@ -828,9 +829,18 @@ public: if (!*args) return false; - uint32 phaseId = uint32(atoul(args)); + char* phaseText = strtok((char*)args, " "); + if (!phaseText) + return false; - if (!sPhaseStore.LookupEntry(phaseId)) + uint32 phaseId = uint32(strtoul(phaseText, nullptr, 10)); + uint32 visibleMapId = 0; + + char* visibleMapIdText = strtok(nullptr, " "); + if (visibleMapIdText) + visibleMapId = uint32(strtoul(visibleMapIdText, nullptr, 10)); + + if (phaseId && !sPhaseStore.LookupEntry(phaseId)) { handler->SendSysMessage(LANG_PHASE_NOTFOUND); handler->SetSentErrorMessage(true); @@ -838,13 +848,29 @@ public: } Unit* target = handler->getSelectedUnit(); - if (!target) - target = handler->GetSession()->GetPlayer(); + if (visibleMapId) + { + MapEntry const* visibleMap = sMapStore.LookupEntry(visibleMapId); + if (!visibleMap || visibleMap->rootPhaseMap != int32(target->GetMapId())) + { + handler->SendSysMessage(LANG_PHASE_NOTFOUND); + handler->SetSentErrorMessage(true); + return false; + } - target->SetInPhase(phaseId, true, !target->IsInPhase(phaseId)); + if (!target->GetPhaseShift().HasVisibleMapId(visibleMapId)) + PhasingHandler::AddVisibleMapId(target, visibleMapId); + else + PhasingHandler::RemoveVisibleMapId(target, visibleMapId); + } - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->SendUpdatePhasing(); + 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 250d6c798c2..6b2480b45ef 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -32,6 +32,7 @@ EndScriptData */ #include "CreatureAI.h" #include "Player.h" #include "Pet.h" +#include "PhasingHandler.h" template struct EnumName @@ -287,8 +288,7 @@ public: return false; } - //creature->CopyPhaseFrom(chr); // creature is not directly added to world, only to db, so this is useless here - + PhasingHandler::InheritPhaseShift(creature, chr); creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); ObjectGuid::LowType db_guid = creature->GetSpawnId(); @@ -718,18 +718,8 @@ public: if (CreatureData const* data = sObjectMgr->GetCreatureData(target->GetSpawnId())) { - handler->PSendSysMessage(LANG_NPCINFO_PHASES, data->phaseid, data->phaseGroup); - if (data->phaseGroup) - { - std::set _phases = target->GetPhases(); - - if (!_phases.empty()) - { - handler->PSendSysMessage(LANG_NPCINFO_PHASE_IDS); - for (uint32 phaseId : _phases) - handler->PSendSysMessage("%u", phaseId); - } - } + handler->PSendSysMessage(LANG_NPCINFO_PHASES, data->phaseId, data->phaseGroup); + PhasingHandler::PrintToChat(handler, target->GetPhaseShift()); } handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor()); @@ -1078,12 +1068,8 @@ public: return false; } - creature->ClearPhases(); - - for (uint32 id : 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(-int(phaseGroupId)); creature->SaveToDB(); @@ -1114,8 +1100,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 7e6ddb25064..2c4221203eb 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -1142,15 +1142,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 HandleReloadRBACCommand(ChatHandler* handler, const char* /*args*/) { TC_LOG_INFO("misc", "Reloading RBAC tables..."); diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index 4327ac4c52c..5b1decd2984 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -25,6 +25,7 @@ EndScriptData */ #include "Chat.h" #include "Language.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "ScriptMgr.h" #include "WaypointManager.h" @@ -667,7 +668,7 @@ public: return false; } - wpCreature->CopyPhaseFrom(chr); + PhasingHandler::InheritPhaseShift(wpCreature, chr); wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); @@ -881,7 +882,7 @@ public: return false; } - wpCreature->CopyPhaseFrom(chr); + PhasingHandler::InheritPhaseShift(wpCreature, chr); // Set "wpguid" column to the visual waypoint stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_WPGUID); @@ -945,7 +946,7 @@ public: return false; } - creature->CopyPhaseFrom(chr); + PhasingHandler::InheritPhaseShift(creature, chr); creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); if (!creature->LoadCreatureFromDB(creature->GetSpawnId(), map)) @@ -996,7 +997,7 @@ public: return false; } - creature->CopyPhaseFrom(chr); + PhasingHandler::InheritPhaseShift(creature, chr); creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); if (!creature->LoadCreatureFromDB(creature->GetSpawnId(), map)) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp index 4a0a96092b6..023c71f7d35 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp @@ -1172,7 +1172,7 @@ public: 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); } @@ -1290,7 +1290,7 @@ public: { 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); hyjal_trashAI::JustDied(killer); diff --git a/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp b/src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp index ab3c6fdd4f6..d8eb7629658 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()); const_cast(GetExplTargetDest())->Relocate(x, y, z); GetHitDest()->Relocate(x, y, z); diff --git a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_high_prophet_barim.cpp b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_high_prophet_barim.cpp index 1da7989686b..cb6b0a966e1 100644 --- a/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_high_prophet_barim.cpp +++ b/src/server/scripts/Kalimdor/LostCityOfTheTolvir/boss_high_prophet_barim.cpp @@ -18,6 +18,7 @@ #include "ScriptMgr.h" #include "lost_city_of_the_tolvir.h" #include "ObjectMgr.h" +#include "PhasingHandler.h" #include "Player.h" #include "ScriptedCreature.h" #include "SpellAuraEffects.h" @@ -289,8 +290,7 @@ public: if (Creature* barim = _instance->GetCreature(DATA_HIGH_PROPHET_BARIM)) barim->AI()->JustSummoned(me); - for (uint32 id : GetPhasesForGroup(PHASE_GROUP_ENCOUNTER_1)) - me->SetInPhase(id, false, true); + PhasingHandler::AddPhaseGroup(me, PHASE_GROUP_ENCOUNTER_1, true); DoCastSelf(SPELL_REPENTANCE_SCRIPT_1, true); _events.ScheduleEvent(EVENT_COPY_WEAPON, Seconds(2)); @@ -439,7 +439,7 @@ public: me->SetReactState(REACT_PASSIVE); DoZoneInCombat(); DoCastSelf(SPELL_BIRTH, true); - me->SetInPhase(PHASE_ID_REPENTANCE, true, false); + PhasingHandler::AddPhase(me, PHASE_ID_REPENTANCE, true); } void JustEngagedWith(Unit* /*who*/) override @@ -455,8 +455,7 @@ public: if (Creature* barim = _instance->GetCreature(DATA_HIGH_PROPHET_BARIM)) barim->AI()->JustSummoned(summon); - for (uint32 id : GetPhasesForGroup(PHASE_GROUP_ENCOUNTER_1)) - summon->SetInPhase(id, false, true); + PhasingHandler::AddPhaseGroup(summon, PHASE_GROUP_ENCOUNTER_1, true); } void JustDied(Unit* /*killer*/) override diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp index 29611c23cd9..6aad1be5363 100644 --- a/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp +++ b/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp @@ -268,7 +268,7 @@ class boss_high_priestess_azil : public CreatureScript me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_CASTING_VISUAL); me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_ENERGY_SHIELD); Position pos = me->GetPosition(); - pos.m_positionZ = me->GetMap()->GetHeight(me->GetPhases(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); + pos.m_positionZ = me->GetMap()->GetHeight(me->GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); me->GetMotionMaster()->MovePoint(POINT_GROUND, pos); break; } diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp index cd34681aa33..d1dbe8a65ac 100644 --- a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp +++ b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp @@ -266,7 +266,7 @@ class boss_slabhide : public CreatureScript case EVENT_LAND: { Position pos = me->GetPosition(); - pos.m_positionZ = me->GetMap()->GetHeight(me->GetPhases(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); + pos.m_positionZ = me->GetMap()->GetHeight(me->GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_LAND, pos); break; } @@ -479,7 +479,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_amanitar.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp index 4a651769fd9..0a3c2086d67 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp @@ -88,7 +88,7 @@ class boss_amanitar : public CreatureScript for (uint8 i = 0; i < 30; ++i) { Position pos = me->GetRandomNearPosition(30.0f); - pos.m_positionZ = me->GetMap()->GetHeight(me->GetPhases(), pos.GetPositionX(), pos.GetPositionY(), MAX_HEIGHT) + 2.0f; + pos.m_positionZ = me->GetMap()->GetHeight(me->GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), MAX_HEIGHT) + 2.0f; if (Creature* trigger = me->SummonCreature(NPC_TRIGGER, 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 b1423e8aa91..af5dc4f8f43 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp @@ -22,6 +22,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ahnkahet.h" +#include "PhasingHandler.h" #include "Player.h" #include "SpellInfo.h" @@ -142,7 +143,7 @@ public: // clone player->CastSpell(summon, SPELL_CLONE_PLAYER, true); // phase the summon - summon->SetInPhase(spellInfo->Effects[EFFECT_0].MiscValueB, true, true); + PhasingHandler::AddPhase(summon, spellInfo->Effects[EFFECT_0].MiscValueB, true); } } ++insanityHandled; @@ -168,9 +169,9 @@ public: instance->DoStopTimedAchievement(ACHIEVEMENT_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(); @@ -208,7 +209,7 @@ public: return; else { - nextPhase = *visage->GetPhases().begin(); + nextPhase = visage->GetPhaseShift().GetPhases().begin()->Id; break; } } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index fe2bdd35bf4..bea95c5fce3 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -627,7 +627,7 @@ class npc_frost_sphere : public CreatureScript if (me->GetHealth() <= damage) { damage = 0; - float floorZ = me->GetMap()->GetHeight(me->GetPhases(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); + float floorZ = me->GetMap()->GetHeight(me->GetPhaseShift(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); if (fabs(me->GetPositionZ() - floorZ) < 0.1f) { // we are close to the ground 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 ee9092c97ec..30fc14ed5a8 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -804,7 +804,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; @@ -1046,7 +1046,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 717e2e2ace9..04f016e2fbb 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -17,6 +17,7 @@ #include "ObjectMgr.h" #include "ScriptMgr.h" +#include "PhasingHandler.h" #include "ScriptedCreature.h" #include "SpellAuraEffects.h" #include "Cell.h" @@ -636,7 +637,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/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 8dd67e1ff5e..1b6a8c26b3a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -778,7 +778,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 a063663f74e..8f7f6492c4c 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 f933cc5de86..5a4a0bd9d08 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 "ScriptedGossip.h" #include "ScriptedEscortAI.h" #include "ScriptedFollowerAI.h" +#include "PhasingHandler.h" #include "Player.h" #include "SpellInfo.h" #include "WorldSession.h" @@ -1689,7 +1690,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 7a1150af29c..a871f044bf9 100644 --- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp +++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp @@ -529,7 +529,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 3a736f2f02f..6ea3fabb84a 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp @@ -18,6 +18,7 @@ #include "ScriptMgr.h" #include "OutdoorPvPSI.h" #include "WorldPacket.h" +#include "PhasingHandler.h" #include "Player.h" #include "GameObject.h" #include "MapManager.h" @@ -182,8 +183,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId) return true; } - go->CopyPhaseFrom(player); - + PhasingHandler::InheritPhaseShift(go, player); go->SetRespawnTime(0); if (!map->AddToMap(go)) @@ -213,8 +213,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId) return true; } - go->CopyPhaseFrom(player); - + PhasingHandler::InheritPhaseShift(go, player); go->SetRespawnTime(0); if (!map->AddToMap(go)) diff --git a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp index f3184bf7807..73029c4d58b 100644 --- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp +++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp @@ -75,7 +75,7 @@ public: void Reset() override { - ground = me->GetMap()->GetHeight(me->GetPhases(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZMinusOffset()); + ground = me->GetMap()->GetHeight(me->GetPhaseShift(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZMinusOffset()); SummonInfernal(); events.ScheduleEvent(EVENT_CAST_SUMMON_INFERNAL, urand(1000, 3000)); }